[CSS翻译]计算颜色:使用纯CSS的动态配色

4,941 阅读7分钟

原文地址:una.im/css-color-t…

原文作者:una.im/

发布时间:2019年12月5日

**你知道吗,你可以在不使用JavaScript或CSS预处理器的情况下构建自定义动态颜色主题!?有了CSS自定义属性、HSL颜色和一些calc()乐趣的魔力,你也可以创建无依赖性的自定义主题。这意味着我们可以支持任何框架或网络技术,而不需要在代码库中添加任何赘肉。为CSS欢呼 **

演示

codepen.io/una/embed/V…

在上面的演示中,你可以选择一个主色和辅助色,并仅用vanilla CSS创建整个颜色系统。该演示中唯一使用的JavaScript是动态改变颜色。

CSS *处理器给我们带来了什么

说到颜色系统,有几个Sass颜色功能是作者觉得有用的。Jackie Balzar有一篇很好的可视化帖子。其中最常见的有

  • lighten()darken()
  • complement()
  • hue()
  • mix()
  • contrast-color()

其中一些变换实际上可以用CSS滤镜重新创建。例如,lightendarken本质上只是HSL中的lightness值(L)。hue变换也只是HSL中的H。补色可以通过取色相的倒数来计算(即加减180,这样可以将色相变换到360度色轮的另一边。在我们的CSS中使用calc(),以及自定义属性,让我们可以基于一个单一的值来应用这些转换。

在这篇博文中(就像上面的演示一样),我将向你展示如何重新创建lighten()darken()complement(),甚至是三元色彩,所有这些都是使用CSS自定义属性与calc()函数来实现的。我还将展示一种用于color-contrast()的黑客技术。这将在所有现代浏览器中工作,但你仍然需要使用一个预处理器来支持旧的浏览器,如Internet Explorer 11。

设置

要开始,我们需要将我们的颜色分解成色相、饱和度和明度值(如果你想更进一步,你还可以分解出alpha值)。这意味着颜色red的变量,或hsl(0,100%,50%)会是这样的。

初始自定义属性声明:

--colorPrimary: hsl(0, 100%, 50%);

带有HSL值的自定义属性声明。

--colorPrimary-h: 0;
--colorPrimary-s: 100%; --colorPrimary-h: 0; --colorPrimary-s: 100%;
--colorPrimary-l: 50%;

--colorPrimary: var(-colorPrimary-h), var(-colorPrimary-s), --colorPrimary-l);

用HSL调整数值

厉害!所以现在我们可以使用这些值来进行调整。我们是否应该从重新创建亮化暗化功能开始呢?为什么不呢?

首先,我们需要确定我们想要变亮和变暗的程度,所以让我们继续并将其保存为额外的自定义属性。

--lighten-percentage: 20%;
--darken-precentage: 15%;

一旦我们确定了我们的变换,现在我们就可以写新的值了。我们要用这样的计算来调整亮度: calc(var(--colorPrimary-l) + var(--lighten-percentage))

全部加在一起就是这样的。

--colorPrimary--light: var(--colorPrimary-h), var(--colorPrimary-s), calc(var(--colorPrimary-l) + var(--lighten-percentage)));

虽然这看起来有点啰嗦,但本质上我们所做的就是使用基本色调和饱和度值,并通过在原始值上添加新的亮度百分比来调整亮度值。

对于暗度函数,我们可以用同样的方法减去明度(或者如果你把暗度百分比设置为负值,则添加它)。

--colorPrimary--dark: var(--colorPrimary-h), var(--colorPrimary-s), calc(var(--colorPrimary-l) - var(--darken-percentage)));

获取补色和三原色

来源:tallys.github.io/color-theor…

要想得到补色或三原色的色调,我们需要调整主色的色调而不是明度。我们可以设置单独的变量,但也可以走捷径,记住HSL中的色轮从0到360。这意味着加减180就能得到补色。

--colorPrimary--complement: calc(var(--colorPrimary-h) + 180), var(--colorPrimary-s), var(--colorPrimary-l));

对于三原色,我们将360切成三份,也就是说,我们可以通过分别加减120和240来得到第一个和第二个三原色。

--colorPrimary--triad1: calc(var(--colorPrimary-h) + 120), var(--colorPrimary-s), var(--colorPrimary-l));

--colorPrimary--triad2: calc(var(--colorPrimary-h) + 240), var(--colorPrimary-s), var(--colorPrimary-l));

对于类比色相,我们可以确定每个色相的色调调整,并根据我们的喜好得到一个不错的类比色方案。

再创Mix()

mix()混合模式比起lighten()darken()之类的东西要棘手一些,但完全可以通过HSL计算来完成!

codepen.io/una/embed/q…

为了混合颜色,我们需要两种颜色来混合,所以我们来分解一下。

--color-1-h: 0;
--color-1-s: 100%;
--color-1-l: 50%;

--color-2-h: 50;
--color-2-s: 80%;
--color-2-l: 50%;

然后,我们可以得到这两种颜色的平均值。

--avg-1-2-h: calc((var(--color-1-h) + var(--color-2-h)) / 2);
--avg-1-2-s: calc((var(--color-1-s) + var(--color-2-s)) / 2);
--avg-1-2-l: calc((var(--color-1-l) + var(--color-2-l)) / 2);

最后,我们可以写出我们的混合颜色。

--mixed-color: hsl(var(--avg-1-2-h), var(--avg-1-2-s), var(--avg-1-2-l));

创建一个颜色对比函数

CSS处理器提供的另一个关键功能是逻辑值,它允许我们根据其背景计算出可访问的颜色,这就是contrast-color()函数。这个函数需要一系列的值:要对比的底色、一个浅色的值和一个深色的值,并将返回所提供的值中与底色对比较大的那一个。虽然目前我们不能直接在纯CSS中建模,但我们可以绕过它。

我使用的这个技术来自Facundo Corradini,所以请不要把功劳归于我! 😄

首先,我们设置一个对比度阈值。

--contrastThreshold: 60%;

然后,当我们从页面顶部的演示中更新每个框中的颜色值时,我们测试亮度值,以确定它是否符合 "光 "的对比度阈值。如果阈值高于基础色的亮度,颜色就会返回亮色,因为我们将亮度结果乘以-100。例如,如果我们的明度是40,而contrastThreshold是60,那么40 - 60 = -20,所以当我们将该明度乘以-100时,就变成了2000,结果是白色,因为当明度为100或更高时,白色就会显示出来。

当光度高于 contrastThreshold 时,则会发生相反的情况。如果我们的亮度是90,而contrastThreshold是60,结果是30,所以当我们把这个正值乘以-100,我们得到的亮度是-3000,这意味着结果是黑色的,因为亮度低于0。

然后,我们将这个亮度作为HSL中的 "L "返回到这个背景色之上的颜色值。它看起来像这样。

.primary {
  background: var(--colorPrimary);
  
  --switch: calc((var(--colorPrimary-l) - var(--contrastThreshold)) * -100);
  color: hsl(0, 0%, var(--switch));
}

如果你想看到它的行动,请查看页面顶部的演示。

请记住,因为HSL是计算机理解亮度的方式,而不是用户理解亮度的方式,所以这种技术并不完美,它清楚地告诉我们自定义属性和计算函数仍有不足之处。

CSS颜色函数的未来

......这正是为什么我们需要网络上的颜色修改功能! 如果这些东西真的能在本机工作,那不是很好吗?如果我们不需要把所有的东西都分解成单独的HSLA值,也不需要在色彩对比上做手脚,那该多好?

许多设计系统和网站都依赖于颜色的修改,CSS工作组正在倾听,并致力于确定如何将颜色调整和修改功能带到网络浏览器中。

我希望你喜欢这篇文章,或者学到一些新的东西! 如果你在你的设计系统或用户界面中使用了颜色修改,我很想听听你的意见! 请在推特上给我@una或在下面留言!