配了三年配色,每次品牌色一换就要回头过一遍文字颜色——今天 CSS 一个函数把这件事彻底原生化了

配了三年配色,每次品牌色一换就要回头把文字颜色全部过一遍——light 主题配深色文字、dark 主题配浅色文字,同样的组件要维护两套规则。今天一个 CSS 函数把这个彻底原生化了。

设计系统的工程师每天都在处理这个问题:同一个按钮组件,在不同品牌色下文字该显示黑色还是白色?

传统解法:

  • 手工维护两套 CSS class
  • 用 Sass/Less 写颜色函数计算 luminance
  • 用 JS 动态判断背景色亮度再写回去

不管哪种都要写额外代码,而且换主题色的时候要把所有配对关系重新过一遍。

contrast-color() 是什么

Chrome 147+/Firefox 146+/Safari 26+/Edge 147+ 全部支持,2026 年 4 月进入 Baseline,全球约 90% 覆盖率。

background-color: var(–brand-color);
color: contrast-color(var(–brand-color));

传什么颜色都行:hex、rgb、hsl、oklch、color-mix() 混色、CSS 变量,浏览器会自动比较这个颜色与黑色的对比度、与白色的对比度,返回得分更高的那个。

WCAG AA 标准(4.5:1)是硬门槛,两个候选都达标的返回对比度更高的那个。如果黑白得分完全相同(比如恰好是中灰色),返回 white。目前只返回 black 或 white,不支持自定义候选色。

实战场景

品牌色按钮:

–brand: #6b28cc;
background-color: var(–brand);
color: contrast-color(var(–brand));

只要改一行 –brand,整套按钮文字颜色就自动适配。

暗色模式无缝切换:

亮色背景自动配黑字,暗色背景自动配白字,一个声明搞定。

用户自定义主题:

card 组件的背景色来自用户头像色,文字颜色自动适配。

局限

  • 只返回黑白,中间色调(比如浅蓝)无论哪个都是弱对比
  • 不考虑字号,WCAG 对大字号(18px+ 或 14px bold)要求 3:1,但 contrast-color() 不区分
  • 渐变背景不适用,一张渐变背景没法给出一个对比度数字
  • 背景图片上的文字无法处理,只能处理纯色

渐进增强写法:

先写 fallback,再让支持 contrast-color() 的浏览器覆盖。

结论

contrast-color() 不是万能无障碍药方,但它把设计系统里最常见的按钮/标签/徽章类组件的配色问题用一个声明解决了。

下一步:

  1. 翻一下自己的设计系统,找到这类组件,把手写的黑白配对换成 contrast-color()
  2. 注意那些用 oklch 或 color-mix 生成的动态色,contrast-color() 对它们同样生效
  3. 重要文字(正文、说明)不要依赖这个函数,它只管能看清,不管满足 WCAG AA

评论区

0 条评论

登录后可评论。