relative-color()仅能解析颜色通道,不能计算对比度;需配合color-mix()按LCH亮度插值黑白文字色,并声明@property支持,否则无效。

relative-color() 不能直接算对比度,它只负责“拆解颜色”
很多人看到 relative-color() 就以为能自动选黑/白字——其实它只是个“颜色结构化解析器”,类似 JS 的解构赋值。它本身不计算亮度、不判断可读性,也不生成新色,只把一个已知颜色按 LCH/RGB/HSL 等格式拆成独立通道变量(比如 l、c、h 或 r、g、b),供后续运算使用。
必须搭配 color-mix() 或条件逻辑(如 light-dark())才能产出可用文字色;单独写 color: relative-color(var(--bg) l c h / 1); 和直接写 color: var(--bg); 效果完全一样。
用 relative-color() + color-mix() 实现亮度驱动的黑白切换
这是目前 Chrome 111+、Safari 16.4+ 支持的轻量级纯 CSS 方案,核心思路是:提取背景色的亮度 l,再按该亮度在黑与白之间插值。
-
@property必须声明,否则relative-color()无法解析自定义属性::root { --bg: #4a90e2; @property --bg { syntax: "<color>"; inherits: false; initial-value: black; } } - 提取并映射亮度:
.text { color: color-mix(in lch, white calc(100% - l(from var(--bg))), black l(from var(--bg))); }这行代码意思是:亮度越低(l越小),越倾向黑色;亮度越高(l越大),越倾向白色 - 注意:LCH 的
l值范围是 0–100,但color-mix()的权重必须是百分比,所以要手动做calc(100% - l)转换
为什么不能只靠 lightness() 或 HSL 的 L 判断文字色
HSL 的 lightness() 是均匀数学分割,和人眼感知亮度无关。例如:
立即学习“前端免费学习笔记(深入)”;
-
#ffcc00(亮黄)的 HSLlightness()≈ 60%,按传统逻辑会配黑字——但实际黑字发灰、对比度仅 ~2.1:1,远低于 WCAG AA 要求的 4.5:1 -
#e6f7ff(极浅蓝)的 HSLlightness()≈ 95%,却仍能清晰显示黑字,因为其相对亮度(WCAG luminance)高达 ~0.92 - 真正可靠的依据是 WCAG 的
relative-luminance公式:0.2126 * R + 0.7152 * G + 0.0722 * B(经 gamma 校正后),而relative-color()在 LCH 空间中提取的l更接近该感知亮度,但不是等价替换
降级方案必须显式提供 fallback,且不能依赖 JS
当浏览器不支持 relative-color() 或 color-mix() 时,CSS 会直接忽略整条声明。这意味着你必须提前写好兜底规则:
- 用
light-dark()最简单:.text { color: light-dark(#000, #fff); background-color: var(--bg); }它不看背景色,只看系统偏好,适合深色模式切换场景,但不解决单个卡片动态背景问题 - 用
prefers-contrast媒体查询增强可访问性:@media (prefers-contrast: more) { .text { color: #000 !important; } } - 绝对不要把 fallback 写在
color-mix()后面指望层叠生效——CSS 不会“回退到上一条 color 声明”,只会跳过整条不支持的规则
真正棘手的是渐变背景或图片背景:此时 CSS 无法获取真实渲染色,relative-color() 失效,必须交由 JS 获取 canvas 像素或使用 getComputedStyle() + background-image 解析逻辑——这部分没有标准解法,容易漏掉透明通道或混合模式影响。


















