在建立你的下一个项目时,当然不缺乏可使用的设计系统。在IBM的Carbon、Wanda和Nord之间,有很多了不起的设计系统可以选择。然而,虽然每个系统都有自己的细微差别和意见,但大多数系统都有一个相似的目标--简化开发过程,创造精美的可访问用户界面。
这是一个令人钦佩的目标,而且,说实话,这也促使我把自己的事业转向设计系统。但是,许多设计系统的基础的一个核心特征是对主题的可扩展性。为什么不呢?如果没有一些品牌的灵活性,每个使用特定系统的产品看起来都是一样的,就像2012年的Bootstrap一样。
虽然提供对自定义主题的支持是至关重要的,但它也使最善意的系统的可访问性受到实施的摆布。有些团队可能会花上几周,甚至几个月的时间,为品牌重塑定义他们理想的调色板。他们会对每一个色调和颜色组合进行研究,以确保所有的东西都是可靠的,信息丰富的,并且是可访问的。
其他人则根本无法或不愿这样做。
alt 要求在img ,或在label ,或在input ,是一回事,但强制执行无障碍调色板是完全不同的野兽。它是一个有着锯齿状的黄牙、火红的眼睛和绿色的鳞片的野兽,它的身体就像鳄鱼的盔甲一样。
至少你认为它是。就你所知,它可能是一只只有模糊不清的黑色和稍暗的黑色的野兽。
这就是问题所在。
CSSColor-Contrast() 功能
构建包容性产品并不意味着支持设备,而是支持使用设备的人。
CSScolor-contrast() 功能是一个实验性功能,目前是色彩模块5的一部分。它的目的--也是本文激动人心的原因--是为了从一个列表中选择与基色对比度最大的颜色。

在这篇文章中,我们将第一个参数称为 "基色",第二个参数称为 "颜色列表"。这些参数可以接受浏览器支持的CSS颜色格式的任何组合,但要注意不透明性。还有一个可选的第三个参数,但我们稍后再看这个。首先,让我们定义一下我们所说的这是一个实验性的功能是什么意思。
在撰写本文时,color-contrast() 功能只在Safari技术预览浏览器中可用。该功能可以通过Develop 和Experimental Features 菜单进行切换。下面的演示只有在该浏览器中启用该功能时才能工作。所以,如果你想切换,现在不是最坏的时机。
现在,有了基本的语法、术语和支持,让我们深入了解一下。🤿
让我感兴趣的颜色是Rachel Andrew在AxeCon 2022的演讲 "考虑到可访问性的新CSS"中向我介绍了color-contrast() 。我把这个功能潦草地记在了我的笔记本上,并在上面圈了好几遍,以使它变得生动。因为我最近一直在思考设计系统的问题,我想知道这个小小的CSS功能在这个背景下能产生多大的影响。
在她的演讲中,Rachel通过根据背景动态地定义文本颜色来演示了这个新功能。因此,让我们也从这里开始,在article 上设置背景和文本颜色。
article {
--article-bg: #222;
background: var(--article-bg);
color: color-contrast(var(--article-bg) vs #FFF, #000);
}
我们首先将--article-bg 自定义属性定义为深灰色,#222 。然后,该属性在color-contrast() 函数中被用作基色,并与颜色列表中的每一项进行比较,找出对比度最高的值。
| 基色 | 颜色列表 | 对比度 |
|---|---|---|
#222 | #FFF | 15.9 |
#222 | #000 | 1.31 |
因此,文章的color 将被设置为白色,#FFF 。
但这还可以更进一步。
我们可以通过使用一个函数的结果作为另一个函数的基色来有效地连锁color-contrast() 。让我们扩展一下article 的例子,定义相对于其文本的::selection 颜色。
article {
--article-bg: #222;
--article-color: color-contrast(var(--article-bg) vs #FFF, #000);
background: var(--article-bg);
color: var(--article-color);
::selection {
background: color-contrast(var(--article-color) vs #FFF, #000);
}
}
现在,随着文本颜色的定义,其选择背景也将被定义。

color-contrast() 的可选第三个参数定义了一个目标对比度。该参数可以接受一个关键字--AA,AA-large,AAA, 和AAA-large --或者一个数字。当定义了目标对比度后,从颜色列表中选择第一个符合或超过它的颜色。

这就是color-contrast() ,可以真正赋予设计系统强制执行特定水平的可访问性。
让我们把它分解一下。
.dark-mode {
--bg: #000;
--color-list: #111, #222;
}
.dark-mode {
background: var(--bg);
color: color-contrast(var(--bg) vs var(--color-list));
&.with-target {
color: color-contrast(var(--bg) vs var(--color-list) to AA);
}
}
当两个color 的声明被比较时,神奇的事情发生了。
基础.dark-mode 类不使用目标对比。这导致color 被定义为#222 ,即相对于它的基色黑色而言,颜色列表中的最高对比度值。不用说,1.35 的对比度可能是最高的,但它远不是可访问的。
与此相比,当.dark-mode 和.with-target 类被合并,并指定了一个目标对比度。尽管使用相同的基色和颜色列表,但结果却大不相同。当颜色列表中没有任何值符合AA (4.5) 的目标对比度时,该函数会选择一个符合的值。在这种情况下,就是白色。
这就是color-contrast() 的潜力最大的地方。
在设计系统的背景下,这将允许一个系统以非常细微的控制来执行一个颜色可及性的水平。这个级别也可以是一个:root-scoped的自定义属性,允许目标对比度是动态的但又是全局的。在产品方面有一种真正的控制感,但这在实施过程中是有代价的。
代码和结果之间存在着逻辑上的脱节。代码并没有传达白色将是结果。当然,在产品方面的控制会转化为实施方面的不确定性。如果一个人正在使用一个设计系统,并将特定的颜色传递给他们的主题,为什么会用黑色和白色来代替?
第一个问题可以通过更深入地了解color-contrast() ,第二个问题可以通过清晰的、可沟通的文档来缓解。然而,在这两种情况下,这都将期望的负担转移到了实现方面,这并不理想。
在某些情况下,明确的控制将证明成本的合理性。然而,color-contrast() ,在所有情况下都需要考虑其他缺点。
并非所有闪亮的都是金子
与任何实验性或新功能一样,有不可避免的缺点需要考虑,color-contrast() 也不例外。
颜色和视觉对比度是不同的东西
当使用color-contrast() ,根据其背景来确定文本的颜色时,该功能正是在比较--颜色。color-contrast() 不考虑的是可能影响视觉对比的其他样式,如字体大小、重量和不透明度。
这意味着有可能有一种颜色搭配在技术上符合特定的对比度阈值,但由于其大小太小,重量太轻,或其不透明度太高,仍然会导致文字无法访问。
要了解更多关于无障碍排版的信息,我强烈推荐Carie Fisher的讲座:"无障碍排版要点"。
自定义属性和回退
由于CSS自定义属性支持当属性未被定义时的回退值,因此使用color-contrast() 作为渐进式增强似乎是一个好方法。
--article-color: color-contrast(#000 vs #333, #FFF);
color: var(--article-color, var(--fallback-color));
如果不支持color-contrast() ,--article-color 属性就不会被定义,因此就会使用--fallback-color 。不幸的是,这并不是工作方式。
在不支持的浏览器中会发生一件有趣的事情--自定义属性将与函数本身一起被定义。下面是一个来自Chrome DevTools的例子。

因为--article-color 属性在技术上被定义了,所以回退不会被触发。
然而,这并不是说color-contrast() 不能被逐步使用。它可以与@supports() 函数配对,但如果你决定这样做,就要注意了。尽管它可能很令人兴奋,但由于支持有限,而且有可能对语法和/或功能进行修改,最好还是不要在整个代码库中撒上这个小宝石。
@supports (color: color-contrast(#000 vs #fff, #eee)) {
--article-color: color-contrast(var(--article-color) vs #fff, #000);
}
最高的对比度并不意味着可访问的对比度
尽管color-contrast() 可以提供对颜色和主题的控制,但仍有一些限制。当该函数将基色与列表进行比较,并且没有指定目标对比度时,它将选择最高对比度的值。仅仅因为这两种颜色提供了最大的对比度,并不意味着它是一个可访问的颜色。
h1 {
background: #000;
color: color-contrast(#000 vs #111, #222);
}
在这个例子中,背景颜色为黑色。#000 ,与两种深浅不一的深灰色进行对比。虽然#222 会因为具有 "最大 "的对比度而被选中,但将它与黑色搭配在一起就不是什么好事了。
没有梯度支持
事后看来,用color-contrast() 来尝试渐变,也许是有点野心勃勃。然而,通过一些测试,似乎梯度不被支持。我想了想,这是有道理的。
如果一个梯度从黑色过渡到白色,那么基色是什么?而且它不需要与内容的位置相对应吗?这并不是说功能可以解释用户界面。然而,Michelle Barker已经试验过将CSScolor-mix() 和color-contrast() 一起使用,以支持这种确切的用例。
不是你,color-contrast() ,是我。嗯,实际上是梯度,但你知道我的意思。
结束语
那是很多的代码和演示,所以让我们退一步回顾一下color-contrast() 。
这个函数将一个基色与一个颜色列表进行比较,然后选择对比度最高的值。此外,它还可以将这些值与目标对比度进行比较,并选择第一个符合该阈值的颜色或使用符合该阈值的动态颜色。将这一功能与渐进式增强技术结合起来,我们就有了一个可以大幅提高网络可及性的功能。
我相信color-contrast() ,还有很多未开发的领域和用例,所以我想用一些额外的想法和/或问题来结束这篇文章。
在处理不同的颜色模式,如浅色、深色和高对比度时,你如何看待这一功能的利用?targetContrast 基于React的设计系统能否在其ThemeProvider ,以便在主题不足的情况下执行可访问性?会不会有一个用例,让函数返回最低的对比度值来代替?如果有两种基本颜色,这个函数是否可以用来找到它们之间的最佳对比值?
你有什么看法?