让 浏览器智能选择颜色?CSS 这个新功能太聪明了!
zhezhongyun 2025-06-23 23:37 49 浏览
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
1.Webkit 宣布引入 contrast-color()
2025 年 5 月 13 日,Webkit 官网发布了一个全新的 CSS 函数,即 contrast-color()。
有了 contrast-color(),开发者只需编写简单的 CSS 即可让浏览器自行判断该颜色应该搭配什么颜色,其工作原理如下:
假设需要构建一个 Web 网站,设计需要大量具有不同背景颜色的按钮,此时可以创建一个名为 --button-color 的变量来处理背景色。然后,根据不同的情况为设计系统中的变量赋值。例如:有时按钮背景色较深,文本颜色应为白色以保证对比度。有时,背景色较浅,文本颜色应为黑色。
虽然可使用新变量来指定文本颜色,并成对定义 --button-color 和 --button-text-color 以确保文本颜色符合预期。但是,在大型项目合作时会变得非常困难。
因此,如果可以直接告诉 CSS 将文本设置为黑白,并让浏览器自行决定最终颜色以保证对比度。此时,开发者就可以只管理各种背景色,而不必单独处理文本颜色。
2. 如何使用 contrast-color()
根据官方描述,该函数的使用非常简单:
color: contrast - color(purple);在上面的代码中,浏览器会将颜色设置为黑色或白色,从而能与紫色形成更好的对比。
接下来首先设置按钮样式,即将按钮的背景色设置为变量,同时将文本颜色定义为与该变量配对的对比色黑色或白色:
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
}此时开发者只需要定义一种颜色,当更改按钮颜色时,浏览器会重新考虑文本应该是黑色还是白色,并选择对比度更高的颜色。
开发者甚至可以使用 contrast-color() 定义悬停颜色,最终用一个变量决定了四种颜色,即默认按钮颜色及其对应的文本,以及悬停颜色及其对应的文本。
:root {
--button-color: purple;
--hover-color: oklch(from var(--button-color) calc(l + .2) c h);
// oklch() 函数表达 Oklab 颜色空间中的给定颜色
}
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
text-box: cap alphabetic;
/* 垂直居中 */
}
// 设置按钮的 hover 背景和文本颜色
button:hover {
background-color: var(--hover-color);
color: contrast-color(var(--hover-color));
}3. 无障碍设计考量和对比度算法
很多开发者可能会误认为 contrast-color() 函数本身就能解决所有对比度无障碍问题 (Contrast Accessibility Concerns),然而事实并非如此。
使用 contrast-color() 函数并不能保证最终的颜色组合无障碍,即很有可能选择了一种与黑色或白色对比度不足的颜色,而确保对比度明显的工作仍然取决于相关人员,例如:设计师、开发者、测试人员等等。
事实上,如果在 Safari 技术预览版 (Safari Technology Preview) 中查看下面的 Demo,就会发现很多与中间色调背景颜色的搭配都无法产生足够的对比度,即浏览器做出了错误的选择。
:root {
--button-color: purple;
}
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
text-box: cap alphabetic;
}
button:hover {
--hover-color: oklch(from var(--button-color) calc(l + 0.2) c h);
background-color: var(--hover-color);
color: contrast-color(var(--hover-color));
}
:root {
color-scheme: light dark;
font-family: Avenir, Montserrat, Corbel, "URW Gothic", source-sans-pro,
sans-serif;
}
main {
height: 100vh;
display: grid;
place-items: center;
}
header {
}
button {
font-family: inherit;
border-radius: 2lh;
padding: 0.5lh 1lh;
border: none;
box-shadow: 0 0 12px rgb(0, 0, 0, 0.3);
font-size: 2rem;
grid-area: 1 / 1;
width: max-content;
}
header {
grid-area: 1 / 1;
place-self: start;
}
label {
display: flex;
align-items: center;
font-weight: 500;
}
input {
aspect-ratio: 1;
height: auto;
border: none;
background-color: transparent;
padding-inline-start: 5px;
}
figure {
}
figcaption {
text-align: center;
margin-block-start: 2lh;
}
dialog {
background-color: rgb(180, 0, 0);
box-shadow: 0 0 10px rgb(0, 0, 0, 0.6);
color: white;
border: 0;
padding: 1lh;
}
dialog::backdrop {
background-color: rgb(0 0 0 / 25%);
}
@supports (color: contrast-color(purple)) {
dialog {
display: none;
}
}下面是页面 HTML 内容:
<main>
<header>
<label>Button color:
<input type="color" colorspace="display-p3"
id="color-picker"
value="purple">
</label>
</header>
<button>This is a button</button>
<!-- <small>The button color is determined by the color picker, while the browser chooses either white or black for text color — whichever provides more contrast.</small> -->
<dialog open class="support-warning">This browser does not support <code>contrast-color()</code>. Try this demo in a browser that does, like Safari Technology Preview.</dialog>
</main>例如: #317CFF 蓝色背景会返回黑色的对比色,而白色显然更合适。
主要的原因在于:
- Safari 技术预览版使用的是 WCAG 2 中正式定义的对比度算法,如果将蓝色放入 WebAIM 中颜色对比度检查器中,其明确表示使用黑色而非白色作为文本颜色。WCAG 2 是当前 Web 可访问性的权威标准,因此许多地方的法律都要求使用黑色。
- WCAG 2 算法计算出 #317CFF 上的黑色对比度为 5.45:1,而 #317CFF 上的白色对比度为 3.84:1,contrast-color() 函数选择了前者数值较大的选项。
因此,当运行 WCAG 2 算法时,黑色文本在数学上具有更高的对比度。但当人类观看这些组合时,显然黑色对比度更低。WCAG 2 的颜色对比度算法长期以来一直饱受诟病,而将 WCAG 更新到 3 级的核心驱动力就是改进对比度算法。
无障碍感知对比度算法 (Accessible Perceptual Contrast Algorithm,APCA) 是一种预测对比度的新方法,适用于新兴的 Web 标准 (WCAG 3),用于确定可读性对比度。APCA 源自 SAPC(S-LUV 高级预测色彩),后者是一种面向无障碍的色彩外观模型,专为自发光显示器设计。
无障碍感知对比度算法 (Accessible Perceptual Contrast Algorithm ,APCA) 是可能被纳入 WCAG 3 的候选算法之一,开发者目前已经可以使用 apcacontrast.com 上的 APCA 对比度计算器试用该算法,下面是该算法在特定蓝色背景上的黑色和白色文本的感受。
该算法将蓝底黑字的 Lc 值评估为 38.7,而蓝底白字的 Lc 值则为 -70.9,忽略符号的情况下,数值越大对比度越高,最终白色文本胜出。
APCA 算法是基于感知对比度,而非简单的数学计算,其考虑到了人类感知对比度时,色相和亮度之间并非呈线性关系这一事实。
幸运的是,contrast-color() 背后的算法可以替换,此功能于 2021 年 3 月在 Safari 技术预览版 122 中首次发布。而当时,谈论更好的算法还为时过早。
CSS 标准仍然要求浏览器使用旧算法,但包含面向未来的说明:
目前仅支持 WCAG 2.1,且已知该算法存在问题,尤其是在深色背景下。该模块的未来修订版可能会引入其他对比度算法。” 关于哪种算法最适合 WCAG 3 的争论仍在进行中,包括对正在考虑的算法的许可的讨论。
因此,在选择调色板时仍需牢记可访问性,如果选择清晰明亮 (clearly-light) 的颜色或清晰明亮的深色 (clearly-dark) 作为对比色,那么 contrast-color() 即使在 WCAG 2 算法的支持下也能符合预期。但在评估与中间色调的对比度时,不同算法的结果会有所不同。
此外,即使更新算法,contrast-color() 函数本身也无法保证可访问性,很多颜色与黑色或白色的对比度永远不够,尤其是在文本尺寸较小或字体较细的情况下。
4. 在现实世界中提供足够的对比度
在考虑色彩对比度时,可以使用 prefers-contrast 媒体查询,其可以确保为每个人提供良好的对比度,即为需要更高对比度的用户提供替代样式。
.contrast {
width: 100px;
height: 100px;
outline: 2px dashed black;
}
@media (prefers-contrast: more) {
.contrast {
outline: 2px solid black;
}
}prefers-contrast 支持以下属性:
- no-preference:表示用户未向系统告知任何偏好设置,此关键字值在布尔上下文中计算为 false
- more:表示用户已通知系统自己更喜欢对比度更高的界面
- less:表示用户已通知系统自己更喜欢对比度较低的界面
- custom:表示用户已通知系统使用一组特定的颜色,并且这些颜色所隐含的对比度不多不少,此值将与 forced-colors: active 的用户指定的调色板匹配
当在变量中定义颜色时,根据不同的条件替换颜色值非常容易。即使用 contrast-color() 函数只需考虑背景色,而无需考虑文本颜色的搭配,浏览器会自行处理。
为了一次性完成所有操作,开发者只需编写以下代码即可(假设会有更好的算法取代 CSS 中的 WCAG 2 算法):
--button-color: #2DAD4E;
/* 蓝色背景色 */
@media (prefers-contrast: more) {
@media (prefers-color-scheme: light) {
--button-color: #419543;
/* darker green background */
}
@media (prefers-color-scheme: dark) {
--button-color: #77CA8B; /* lighter green background */
}
}
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
font-size: 1.5rem;
/* 1.5 * 16 = 24px at normal zoom */
font-weight: 500;
}实际上,由于 contrast-color() 的驱动因素是 WCAG 2 算法,最终可能无法在某些场景下使用。但如果在某些项目中,品牌颜色是深绿色,并且白色、黑色之间的选择是正确的,那么则可能会非常有用。
使用 contrast-color() 在为多个状态或选项,例如:启用 / 禁用、亮 / 暗模式、优先对比度等定义颜色时尤其有用。
5. contrast-color() 能否超越黑白
如果希望浏览器能自动选择除黑白之外的颜色怎么办? 实际上,较新的 contrast-color() 比原始的 color-contrast() 函数大大简化。
由于 WCAG 3 中应使用哪种颜色对比度算法仍在争论中,CSS 工作组 (CSS Working Group) 决定推出一款工具,只需选择黑色或白色与第一个颜色进行对比即可,保持简单方便的同时也方便未来替换。通过将选项列表硬编码为黑白,网站在 WCAG 2 算法被替换后崩溃的可能性大大降低,从而为 CSSWG 提供了所需的灵活性,即使对比度颜色算法已经交付给用户,也能继续进行必要的更新。
未来很可能会出现更复杂的工具来支持更强大的选项,或许可以列出一组自定义颜色选项,让浏览器从中选择而非只选黑白。但是提前交付简易版本,可以让开发者尽快尝鲜。
同时,虽然以上所有示例都显示了彩色背景上的黑白文本,但 contrast-color() 的用途远不止于此。其可以为文本使用自定义颜色,并将背景设置为黑白。或者完全不包含文本,只需定义边框、背景等任何颜色即可。
参考资料
声明:本文内容来自 Jen Simmons 在 2025 年 5 月 13 日发表的文章《How to have the browser pick a contrasting color in CSS》,但是对部分内容添加了自己的理解和修改。
https://webkit.org/blog/16929/contrast-color/
https://css-tricks.com/exploring-color-contrast-for-the-first-time/
https://codepen.io/jensimmons/pen/XJJjKMO?editors=1100
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast
https://github.com/Myndex/SAPC-APCA/?tab=readme-ov-file
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
