css颜色令牌该用oklch(),因其l值基于cie 2002感知亮度,保障跨明暗模式与设备的一致性,但必须严格遵循单位规范、@supports降级结构及插值边界处理,否则比hex更易出错。

直接说结论:CSS颜色令牌该用 oklch(),但必须配好降级和单位——否则比用 #3b82f6 还容易出错。
oklch() 为什么更适合做颜色令牌
颜色令牌(如 --primary、--text-emphasis)本质是设计系统的“语义锚点”,要能跨明暗模式、跨设备保持感知一致性。HEX 和 RGB 是设备相关、非感知均匀的;HSL 的 L 是数学平均,红/绿同 L=50% 实际亮度差三倍;而 oklch() 的 L 是 CIE 2002 校正后的感知亮度坐标,同一 L 值下不同色相视觉明度基本一致。
- 深色模式切换时,只需改
L:比如oklch(62% 0.28 258.5)→oklch(38% 0.28 258.5),文字在浅底/深底上可读性变化平滑 - 禁用态控制,只降
C不动L:避免L一降,浅色文字在浅底上直接“消失” - 生成悬停/按压态时,调
L或C都不会意外发灰——lch()在蓝紫区就容易插值塌陷,oklch()更稳
@supports 检测和 fallback 必须写对顺序
oklch() 不支持时不是报错,而是整条声明被静默跳过。如果 fallback 写错位置,UI 可能全黑或透明。
- 降级色必须写在
@supports块**外部且上方**,不能包在里面 - 检测值必须带单位:
@supports (color: oklch(0% 0 0))✅,@supports (color: oklch(0 0 0))❌(所有浏览器都返回 false) - 绝对不要用
@supports not—— 安卓 WebView 有解析 bug,会直接忽略整块规则 - 别用
oklab()检测,目前所有主流浏览器都返回 false
正确结构:
button {
background-color: #2563eb;
}
@supports (color: oklch(0% 0 0)) {
button {
background-color: oklch(60% 0.28 258.5);
}
}
参数单位错一个,整行失效
这是最常踩的坑:浏览器不报错,也不 fallback,就当那行 CSS 不存在。
-
L必须带%或小数(0.6),但后者仅 Chrome 112+/Firefox 121+/Safari 17.4+ 支持;稳妥起见统一用60% -
C必须是无单位小数,如0.28,写成28%或28都会被忽略 -
H单位只能是纯数字,加deg在 Safari 16.x 和部分安卓 WebView 中解析失败 - alpha 必须用
/分隔:oklch(60% 0.28 258.5 / 0.8)✅,逗号写法oklch(60%, 0.28, 258.5, 0.8)❌
渐变和动画里色相跨 0° 边界要手动拆段
CSS 对 oklch() 渐变不做短弧插值,oklch(0.7 0.25 350) → oklch(0.7 0.25 10) 会经过 360°→0°,中间段色度被拉低,出现灰紫色带。
- 色相差 >180° 时,必须手动拆成两段:
linear-gradient(to right, oklch(0.7 0.25 350), oklch(0.7 0.25 0), oklch(0.7 0.25 10)) - JS 动画中用
oklch()插值也一样,得自己判断角度差,走短弧逻辑 - DevTools 计算样式永远只显示降级后的 sRGB 值,真值靠肉眼比对 + 控制
C ≤ 0.28降低色域漂移风险
真正难的不是写 oklch(),是写对单位、降级结构和插值边界——漏掉任何一个,颜色系统就从“更可控”变成“更不可控”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











