动态主题色最麻烦的不是配色——是背景色一改文字就看不清,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 接管可访问性体验的一个最实际的例子。

评论区

0 条评论

登录后可评论。