你以为按钮背景色配白字还是黑字只能靠猜?今天 CSS 自己会算了
做设计系统的人大概都有过这个经历:设计师给你八个按钮颜色——primary、success、warning、danger……让你保证文字在任何背景上都清晰可读。你怎么配?
手动查对比度工具,一个一个填。设计师哪天把品牌蓝改了,你全部重新算一遍。用户自己选了主题色,你还得写一整套 if-else luminance 判断。
这根本不是前端工程师该干的事。
现在浏览器自己会算了。
对比色这个老问题
给背景配文字颜色,本质上是在问:给定一个背景色,我该用黑色还是白色才能让文字可读?
这其实是个数学题。WCAG 2.1 定义了 relative luminance 的计算公式:
L = 0.2126 × R + 0.7152 × G + 0.0722 × B
然后用对比度公式得出比值。达到 4.5:1 以上才算 AA 级可用。
以前这个逻辑要么靠手查、要么靠 Sass 函数算、要么写一段 JavaScript。CSS 本身是帮不上忙的——直到现在。
contrast-color() 来了
contrast-color() 是 CSS Color Level 5 里的新函数,今年四月正式进入 Baseline 2026,Chrome 147、Firefox 146、Safari 26、Edge 147 全部支持。你现在就可以用。
它的用法简单到不可思议:
button {
background-color: var(--brand-color);
color: contrast-color(var(--brand-color));
}
传进去任何一个颜色,它会自己算出这个背景配黑色还是白色更清晰,返回的就是那个值。任何有效的 CSS 颜色都能传——十六进制、颜色名、custom property、color-mix() 的结果,悉听尊便。
这个函数最初是 CSS 工作组里 Una Kravets 在 2019 年提的提案,经过多年讨论终于落地。
实际用法
设计系统按钮组件:
.btn {
padding: 0.5rem 1.25rem;
border: none;
border-radius: 0.5rem;
font-weight: 600;
background-color: var(--btn-color);
color: contrast-color(var(--btn-color));
}
不管 --btn-color 今天是紫色、黄色还是用户自定义的奇怪品牌色,文字颜色永远自动选最清晰的那个。
暗色模式联动:
:root {
--surface: #f5f5f5;
--text: contrast-color(#f5f5f5);
}
@media (prefers-color-scheme: dark) {
:root {
--surface: #1a1a1a;
}
}
body {
background-color: var(--surface);
color: var(--text);
}
背景随系统暗色模式切换,文字颜色自动跟着变,一行 JS 都不用写。
悬停动态变色:
.card {
background: var(--accent);
color: contrast-color(var(--accent));
transition: background 0.2s;
}
.card:hover {
background: color-mix(in oklch, var(--accent) 70%, white);
/* 背景变浅,文字自动从白切换到黑 */
}
配合 color-mix() 可以做出悬停时背景变亮、文字自动从白变黑的动态效果。颜色渐变链路上的每一步,文字对比度始终保持可读。
有一个坑要注意
这个函数只返回黑色或白色,不是任意颜色。好处是简单,坏处是——中间调背景它救不了。
比如 #2277d3 这个中蓝色,用 contrast-color() 会返回黑色文字,但这个蓝色配黑字其实达不到 WCAG AA 对小字的要求(对比度约 3.9:1)。函数不会报错,只是结果不可读。
官方文档的建议是:用它处理明显偏亮或明显偏暗的背景,不要幻想它能解决所有中间调问题。如果你有中间调配色需求,还是需要自己验证对比度,或者考虑用 OKLCH 的 lightness 反转来做更精细的控制。
渐进增强写法
所有新 CSS 特性推荐写法:
.btn {
background-color: var(--btn-color);
color: #fff; /* 旧浏览器兜底 */
}
@supports (color: contrast-color(red)) {
.btn {
color: contrast-color(var(--btn-color));
}
}
先写一个旧浏览器的 fallback,再用 @supports 在支持的浏览器里升级。线上出了兼容问题也不影响可读性。
怎么验证
浏览器 DevTools 里直接看 computed style,contrast-color() 在支持的环境里会显示最终算出来的具体颜色值(#000000 或 #ffffff),可以逐个组件验证对比度是否达标。
下一步
如果你正在维护一个设计系统或者主题组件库,把那些手写的 luminance 判断逻辑换成这个函数,只需要两分钟。背景色的自定义能力会立刻提升一个档次——设计师改品牌主色不需要再找你对一遍对比度,用户选什么颜色文字都是清晰的。
前端排版和 UI 这件事,CSS 一直在替我们把活儿抢走。现在对比色也算一个了。
评论区
登录后可评论。