动态主题色最麻烦的不是配色——是背景色一改文字就看不清,contrast-color() 把这件事彻底原生化了
动态主题色最麻烦的不是配色——是背景色一改,文字该用黑还是白这件事,以前只能靠 JS 硬算,现在 CSS 自己会了。
contrast-color() 是什么
contrast-color() 是 CSS Color Level 5 里的新函数,接受一个颜色值,返回与它对比度更高的那个——不是灰色,不是半透明色,就是黑或白。
background-color: var(--card-bg);
color: contrast-color(var(--card-bg));
当 --card-bg 是浅色,返回 black;当它是深色,返回 white。浏览器直接算好给你,不用你写一行 JS。
浏览器支持:2026 年已全就绪
这不是实验性功能。contrast-color() 在 2026 年 4 月正式进入 Baseline Widely Available:
- Safari 26(2026 年 3 月)
- Firefox 146(2026 年 4 月)
- Chrome / Edge 147(2026 年 4 月)
三大家主流浏览器全部支持,现在可以大胆用在生产项目里。
它解决的是什么
动态主题色的场景在 2026 年已经非常普遍:用户自定义主题、运营活动色、暗黑模式跟随系统……背景色是运行时才确定的,前端工程师根本不知道它长什么样。传统解法:
function getContrastColor(bgColor) {
const luminance = getLuminance(bgColor);
return luminance > 0.5 ? 'black' : 'white';
}
contrast-color() 一行替代上面这一整套:
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color)); /* 浏览器帮你算 */
}
配合 CSS 变量,主题切换完全不需要 JS:
:root {
--theme-bg: #1a1a2e;
--theme-text: contrast-color(var(--theme-bg));
}
@media (prefers-color-scheme: light) {
:root {
--theme-bg: #f5f5f5;
/* color 自动跟随,不用写 media query */
}
}
body {
background-color: var(--theme-bg);
color: var(--theme-text);
}
它的边界在哪里
contrast-color() 只返回 black 或 white,不是「最合适的颜色」。
它的算法通常满足 WCAG AA(4.5:1),但对中等色调背景(比如纯蓝 #2277d3),返回的黑色在小字体下可能仍然读起来吃力。官方文档里明确说明了这一点:
Mid-tone backgrounds — such as royal blue (#2277d3) — generally don’t provide enough contrast with either black or white for small text.
这不是 bug,是这种方法的天然局限。解法是配合你的设计系统,把背景色的取值范围约束在「明显偏亮」或「明显偏暗」的范围内,让 contrast-color() 每次都能做出正确的判断。
渐进增强写法
.card {
background-color: var(--card-bg);
color: #fff; /* 回退色,兼容旧浏览器 */
}
@supports (color: contrast-color(#fff)) {
.card {
color: contrast-color(var(--card-bg));
}
}
@supports 写法写一次就够了,不需要针对每个颜色单独降级。因为 contrast-color() 只返回 black/white,回退色如果是其中之一,降级体验完全可接受。
和 color-mix() 的关系
contrast-color() 和 color-mix() 都是 CSS Color Level 5 的函数,但解决的是不同的问题。color-mix() 从两个颜色生成第三个颜色(常用于从主色派生副色);contrast-color() 从一个颜色推导出它的可读文字色。它们是互补的——一个管「颜色怎么配」,一个管「文字怎么读」。
配动态主题色最痛苦的不是配色本身——是不知道背景色是什么的时候,文字还能不能看清。contrast-color() 把这个判断从 JS 拿走了,从今往后,你的按钮、文字卡片、标签,只要背景是 CSS 变量的,文字永远会自动保持可读。这是 CSS 接管可访问性体验的一个最实际的例子。
评论区
登录后可评论。