深入了解CSS颜色架构:提升你的网页设计技巧

890 阅读12分钟

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势,学习途径等等。 本文 GitHub github.com/qq449245884… 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

快来免费体验ChatGpt plus版本的,我们出的钱 体验地址:chat.waixingyun.cn 可以加入网站底部技术群,一起找bug,另外新版作图神器已上线 cube.waixingyun.cn/home

这篇文章深入探讨了CSS颜色架构的重要性和实践方法,以帮助开发人员和设计师创建更具吸引力和一致性的网页设计。作者首先介绍了CSS颜色的基础知识,包括颜色表示法、颜色值和颜色选择工具。接着,他强调了良好的颜色架构对于网页的视觉吸引力和用户体验的重要性。

作者提供了一些实用的技巧和指导原则,帮助读者建立和组织有效的颜色架构。他讨论了颜色调色板的设计,包括主色、辅助色和中性色的选择和配对。此外,他强调了在不同设备和主题模式下保持一致性的重要性,并分享了一些工具和资源,帮助读者更好地管理和调整颜色方案。

最后,作者总结了文章的主要观点,并鼓励读者在设计和开发过程中重视颜色架构的重要性。他强调了良好的颜色选择和组织对于网页的整体外观和用户体验的影响。

下面是正文~~~

编程语言中最困难的事情之一就是以易于理解和维护的方式组织代码。

在这篇文章中,我想解释一下我是如何在我们的 Pink Design 项目中工作和组织颜色的。

就像生活中的一切,我们有许多正确的方法,更多的错误的方法来做同样的事情。在我向你展示如何组织我们的CSS变量之前,让我们先讨论在CSS中组织颜色的错误方法。

image.png

注意:我们的一些颜色架构使用Sass预处理。

定义 CSS 颜色变量的错误方法

审查其他CSS架构时,尝试思考哪些低效会使其难以维护。

使用全局变量来代替没有语义意义的所有内容

作者从LinkedIn网站上的:root元素中,通过使用inspect功能,拿了这个小例子。

正如你在下面的示例中所看到的,一个 :root 选择器上有超过 900 个 CSS 变量!在如此广泛的变量列表中找到某些东西几乎是不可能的。

image.png

将颜色与语义名称关联

我经常看到的第二个选项是具有语义名称的全局变量颜色,例如 --header-background-color

定义逻辑全局命名的问题首先在于你有太多的命名。

创建深色模式主题的第二个问题是,网页设计师不遵循特定颜色需要在深色模式下更改为其他颜色的逻辑。这可能会导致创建过多类型的变量,这些变量难以理解或维护。

来自旧版Appwrite控制台1.0的示例:

image.png

此外,全局颜色的覆盖会使代码的调试变得不清晰,在 Chrome 的检查元素中会出现所有覆盖的交叉线。

image.png

了解了这些问题之后,作者考虑如何更好地构建我们的CSS颜色变量。

我们如何决定管理我们的CSS颜色变量

作者主要想法是为色调谱上的每个颜色组家族创建一个CSS变量,以连接每个颜色组(例如蓝色、绿色、橙色和红色)。通过这种方式,我可以更改每个颜色组的主色调,并轻松替换该颜色家族的所有色调。

作者表示,他对这种方法的唯一疑虑在于,设计团队定义的颜色是用十六进制代码表示的,这种代码实际上代表了RGB颜色。当我们需要创建同一色调的不同深浅时,使用这种表示方式会变得比较困难。

image.png

在处理这个问题时,作者选择将HEX/RGB颜色转换为HSL颜色,然后尝试找出每一组颜色的典型色调。

从 HEX/RGB 转换为 HSL

如果我们将信息(蓝色)颜色转换为HSL颜色,我们可以看到所有色调(第一个值)都不同;它们的范围在 188 和 192 之间。

主要思想是将第一个值保留为另一个CSS变量。

为了应对这个挑战,作者决定利用CSS的calc()函数,通过对基础色调值进行加减运算来解决问题。

从每个家族组的主色中取基色色调;在我们的情况下,主色是“100”颜色,信息(蓝色)家族组的色调是189。

image.png

:root {
  --color-info-hue: 189;

  --color-info-10:  var(--color-information-hue) 87% 97%;            /* #F1FCFE */
  --color-info-50:  calc(var(--color-information-hue) + 3) 90% 89%;  /* #C8F2FC */
  --color-info-100: var(--color-information-hue) 100% 38%;           /* #00A7C3 */
  --color-info-120: calc(var(--color-information-hue) + 1) 100% 26%; /* #007187 */
  --color-info-200: calc(var(--color-information-hue) - 1) 87% 12%;  /* #04333A */
}

通过这种方式,作者可以灵活地调整色调,并改变所有由这个色调派生出的颜色。

如何使用这些变量?

使用颜色变量时,每个调用都必须用 hsl() 函数包装。例如:

background-color: hsl( var(--color-info-100) );

作者并未将hsl()函数直接加入到变量中,这是因为他希望在需要的时候能够方便地控制颜色的透明度。

background-color: hsl( var(--color-info-100) / 0.5 ); /* with 50% opacity */

私有本地变量逻辑

由于存在不同的颜色模式(明亮模式和暗黑模式),在大多数情况下,每个部分的颜色在切换模式后都会变化。

在作者的方法中,所有的颜色都是全局的,包括明亮模式和暗黑模式的颜色。为了管理这两种模式的颜色,他添加了本地颜色变量,这些变量会根据当前模式引用全局颜色变量。为了避免全局变量过多导致混乱,他使用了为每个部分设置私有变量的方法。他用 p- 作为前缀来表示一个变量是私有的。

.partial {
    --p-variable-name: value;
}

作者以按钮部分为例,解释了他如何为文本颜色、background-color border-color 设置主要的私有变量。

.button {
    /* Light-mode Theme */
    --p-text-color:   value;
    --p-button-color: value;
    --p-border-color: value;
}

这些变量的使用方式如下:

.button {
    color:            hsl( var(--p-text-color)   ); 
    background-color: hsl( var(--p-button-color) );
    border-color:     hsl( var(--p-border-color) );
}

复杂部分中的变量可以有很多状态。例如,按钮可以有默认、 :hover:focus:active:disabled 状态。这些基本内部变量使用其他内部变量来呈现任何状态。

按钮变量的代码如下:

.button {
    /* Light Theme */
    --p-text-color:            var(--p-text-color-default);
    --p-button-color:          var(--p-button-color-default);
    --p-border-color:          var(--p-border-color-default);

    --p-text-color-default:    var(--color-neutral-5);
    --p-button-color-default:  var(--color-primary-200);
    --p-border-color-default:  var(--color-primary-300);

    --p-text-color-hover:      var(--p-text-color-default);
    --p-button-color-hover:    var(--color-primary-100);
    --p-border-color-hover:    var(--p-border-color-default);

    --p-text-color-focus:      var(--p-text-color-default);
    --p-button-color-focus:    var(--color-primary-200);
    --p-border-color-focus:    var(--color-primary-200);

    --p-text-color-active:     var(--p-text-color-default);
    --p-button-color-active:   var(--color-primary-300);
    --p-border-color-active:   var(--color-primary-300);

    --p-text-color-disabled:   var(--color-neutral-50);
    --p-button-color-disabled: var(--color-neutral-10);
    --p-border-color-disabled: var(--color-neutral-10);
}

定义按钮的状态

现在很好的一点是,只需要在想要更改按钮时更新变量的值。然后,这些变量可以根据部分的状态进行应用。

基本状态定义(使用Sass编写):

/* global Sass Variable */
$disabled: ":disabled, .is-disabled";

.button {
    &:is(:hover) {
        &:where(:not(#{$disabled})) {
            --p-text-color:   var(--p-text-color-hover);
            --p-button-color: var(--p-button-color-hover);
            --p-border-color: var(--p-border-color-hover);
        }
    }
    &:is(:focus-visible) {
        &:where(:not(#{$disabled})) {
            --p-text-color:   var(--p-text-color-focus);
            --p-button-color: var(--p-button-color-focus);
            --p-border-color: var(--p-border-color-focus);
        }
    }
    &:is(:active) {
        &:where(:not(#{$disabled})) {
            --p-text-color:   var(--p-text-color-active);
            --p-button-color: var(--p-button-color-active);
            --p-border-color: var(--p-border-color-active);
        }
    }
    &:where(#{$disabled}) {
            --p-text-color:   var(--p-text-color-disabled);
            --p-button-color: var(--p-button-color-disabled);
            --p-border-color: var(--p-border-color-disabled);
    }
}

作者使用 Sass 变量 $disabled ,这样我就可以在其他元素上使用禁用按钮的样式,比如链接元素。

Sass Code:

/* global Sass Variable */
$disabled: ":disabled, .is-disabled";

.button {
    &:where(#{$disabled}) {
            --p-text-color:   var(--p-text-color-disabled);
            --p-button-color: var(--p-button-color-disabled);
            --p-border-color: var(--p-border-color-disabled);
    }
}

编译后CSS

.button:where(:disabled, .is-disabled) {
      --p-text-color:   var(--p-text-color-disabled);
      --p-button-color: var(--p-button-color-disabled);
      --p-border-color: var(--p-border-color-disabled);    
}
<button class="button" disabled> </button>

<a class="button is-disabled"> </a>

暗黑模式处理

在处理所有按钮的亮色模式状态之后,我们现在想要处理我们的暗色模式状态。

在进行这些操作之前,作者定义了另一个全局的Sass变量,表示暗黑模式的CSS类状态。这个状态类名会在他们的大多数部分中使用,以创造出暗黑模式的独特颜色。

$theme-dark: ".theme-dark";

.theme-dark 类最好直接定义在 <html> 元素上,当然,仅在使用暗模式状态时才这样做。

如果在 <html> 元素上定义它有问题,可以在 <body> 元素上定义。

<body class="theme-dark"> </body>

这样做是为了实现对所有HTML元素的简单全局控制。

局部内的暗模式处理

为了在按钮部分创建暗模式的定义,作者在部分底部添加了这段代码片段:

.button {
   /* regular styles and light-mode definitions */

  #{$theme-dark} & { 
         /* definitions for dark-mode */
     }
}

这个 Sass 代码将编译为这个选择器:

.button { /* regular styles and light-mode definitions */ }

.theme-dark .button { /* definitions for dark-mode */ }

因为所有按钮状态已经声明,唯一剩下的就是在暗模式“部分”中定义状态的私有颜色变量。

如果某些颜色保持不变,则无需在深色模式下进行覆盖。

.button {
  #{$theme-dark} & { 
        /* changed colors */
        --p-border-color-default:  var(--color-primary-200);

        --p-button-color-hover:    var(--color-primary-100);
        --p-border-color-hover:    var(--color-primary-100);

        --p-border-color-focus:    var(--color-primary-300);

        --p-border-color-active:   var(--color-primary-300);

        --p-text-color-disabled:   var(--color-neutral-100);
        --p-button-color-disabled: var(--color-neutral-150);
        --p-border-color-disabled: var(--color-neutral-150);
   }
}

这种方法的好处在于我们不需要重复任何CSS选择器或任何属性定义。

更多类型的按钮

在我们的项目中,我们需要有不同类型的按钮。因为我们已经创建了一个坚实的结构,所以我们只需要根据按钮的新状态来定义那些变量。

定义新状态

要定义一个新状态,我们需要添加新的状态类(.is-secondary):

<button class="button is-secondary"></button>

现在,为了更新新类型按钮的颜色,我们只需覆盖私有颜色:

.button {
   &.is-secondary {
        /* Light Mode */
        --p-text-color-default:   var(--color-neutral-100);
        --p-button-color-default: var(--color-neutral-5);
        --p-border-color-default: var(--color-neutral-30);

        --p-text-color-hover:     var(--p-text-color-default);
        --p-button-color-hover:   var(--color-neutral-10);
        --p-border-color-hover:   var(--p-border-color-default);

        --p-text-color-focus:     var(--p-text-color-default);
        --p-button-color-focus:   var(--p-button-color-default);
        --p-border-color-focus:   var(--transparent);

        --p-text-color-active:    var(--color-neutral-300);
        --p-button-color-active:  var(--color-neutral-30);
        --p-border-color-active:  var(--color-neutral-30);

        --p-text-color-disabled:   var(--color-neutral-50);
        --p-button-color-disabled: var(--p-button-color-default);
        --p-border-color-disabled: var(--color-neutral-30);

        /** Dark Mode **/
        #{$theme-dark} & {
            --p-text-color-default:    var(--color-neutral-5);
            --p-button-color-default:  var(--color-neutral-300);
            --p-border-color-default:  var(--color-neutral-150);

            --p-text-color-hover:      var(--p-text-color-default);
            --p-button-color-hover:    var(--transparent);
            --p-border-color-hover:    var(--color-neutral-120);

            --p-text-color-focus:      var(--p-text-color-default);
            --p-button-color-focus:    var(--p-button-color-default);
            --p-border-color-focus:    var(--transparent);

            --p-text-color-active:     var(--p-text-color-default);
            --p-button-color-active:   var(--p-button-color-default);
            --p-border-color-active:   var(--color-neutral-100);

            --p-text-color-disabled:   var(--color-neutral-100);
            --p-button-color-disabled: var(--p-button-color-default);
            --p-border-color-disabled: var(--color-neutral-150);
        }
    }
}

如你所见,这里只是定义了变量,而没有涉及任何属性或者任何像:hover:focus这样的状态选择器伪类。

事例地址:codepen.io/elad2412/pe…

全局颜色状态

作者强调,在大多数情况下,我们并不希望定义那些在暗黑模式下会改变为其他颜色的全局颜色变量。

然而,尽管这在大多数情况下是正确的,但在某些特定情况下,我们可能希望定义一个状态颜色,使其在明亮模式下呈现一种特定颜色,而在暗黑模式下则呈现另一种颜色。

全局逻辑颜色

为了解决这个问题,作者创造了另一个解决方案,他称之为“全局逻辑颜色”。对于这些全局逻辑颜色,他在一个单独的:root选择器中定义了全局CSS变量,当然,这些变量是引用了其他全局颜色变量的。

对于暗模式,这些变量会被更改为另一个全局颜色变量。例如:

:root {
  /* Global Logic Colors - Light Mode */
  --color-text-info:      var(--color-info-100);
  --color-text-danger:    var(--color-danger-100);
  --color-text-warning:   var(--color-warning-100);
  --color-text-success:   var(--color-success-100);

  --color-border:         var(--color-neutral-10);
  --scroll-color:         var(--color-neutral-50);

  #{$theme-dark} {
    /* Global Logic Colors - Dark Mode */
    --color-text-info:    var(--color-info-120);
    --color-text-danger:  var(--color-danger-120);
    --color-text-warning: var(--color-warning-120);
    --color-text-success: var(--color-success-120);

    --color-border:       var(--color-neutral-200);
    --scroll-color:       var(--color-neutral-150);
  }
}

这些 CSS 变量有两种用法:

部分内部的直接使用

.icon-checked { color: hsl( var(--color-text-success) ); }

作为全局工具类

/* Global Utilities colors classes */
.u-color-text-disabled { color: hsl( var(--color-text-disabled) ); }
.u-color-text-offline  { color: hsl( var(--color-text-offline)  ); }
.u-color-text-info     { color: hsl( var(--color-text-info).    ); }
.u-color-text-danger   { color: hsl( var(--color-text-danger).  ); }
.u-color-text-warning  { color: hsl( var(--color-text-warning). ); }
.u-color-text-success  { color: hsl( var(--color-text-success)  ); }

全局工具类可以直接应用在元素上,而且会根据明亮模式或暗黑模式的主题提供不同的颜色。无论是哪种方式,颜色都会根据颜色模式方案的状态进行更新。

总结

本文主要讨论了定义CSS颜色变量的常见方法以及这些方法存在的问题。在此基础上,我们探讨了如何利用私有变量重新组织CSS变量,从而创建出一个颜色组织良好的CSS架构。

HSL函数介绍

CSS中的HSL函数是一种表示颜色的方法,它使用色相(Hue)、饱和度(Saturation)和亮度(Lightness)三个参数来定义颜色。这种表示方法相对于使用RGB(红、绿、蓝)或十六进制代码来表示颜色更加直观和易于理解。

HSL函数的语法如下: hsl(hue, saturation, lightness)

色相(Hue)是一个0到360之间的角度值,表示颜色在色轮上的位置。0度对应红色,120度对应绿色,240度对应蓝色。 饱和度(Saturation)是一个0到100之间的百分比值,表示颜色的鲜艳程度。0%表示灰色,100%表示全彩色。 亮度(Lightness)是一个0到100之间的百分比值,表示颜色的亮度。0%表示黑色,100%表示白色。 例如,hsl(0, 100%, 50%)表示纯红色。在色轮上的位置是0度(红色),饱和度为100%(全彩色),亮度为50%(半亮度)。

HSL函数在CSS中常用于定义背景颜色、文本颜色和边框颜色等属性。它提供了一种更直观和灵活的方式来表示颜色,使得调整和控制颜色更加方便。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub github.com/qq449245884… 已收录,有一线大厂面试完整考点、资料以及我的系列文章。