OKLCH中“反转”实为语义适配:品牌色如--primary在暗色模式下只降L(如62%→38%)以保蓝调稳定,不发紫偏青;中性色才需真正反转;L是感知亮度标度,单位必须为%,写错即整行静默失效。

OKLCH里“反转”不是取反,而是分层降L
直接把--primary从oklch(62% 0.28 258.5)改成oklch(38% 0.28 258.5),这不是“反转”,是语义适配。真正需要“反转”的只有中性色:比如--text-default、--bg-surface、--border。品牌色如--primary在暗色模式下应保持蓝调稳定,只调L值——否则会发紫或偏青。
关键点在于:OKLCH的L是感知亮度标度(0=黑,1=白),同一L值在所有色相下人眼明暗感受一致。所以降L不等于“变暗”,而是“按人眼感知等量变暗”。
- 亮色模式:
--text-default: oklch(92% 0.015 240) - 暗色模式:
--text-default: oklch(12% 0.015 240)—— L从92%→12%,C/H完全不动 - 别写
oklch(8% ...)或oklch(0.08 ...):前者太暗不可读,后者单位错,整行静默失效
必须用@supports包裹,且fallback写在上面
浏览器对oklch()解析极严格:缺%、C写成百分比、H加deg,都会跳过整条声明,不报错也不降级。
正确结构只能是:
立即学习“前端免费学习笔记(深入)”;
button { background-color: #2563eb; }
@supports (color: oklch(0% 0 0)) {
button { background-color: oklch(60% 0.28 258.5); }
}
-
@supports检测值必须带单位:oklch(0% 0 0)✅,oklch(0 0 0)❌ - 绝对不要写
@supports not——安卓 WebView 有解析 bug,会导致整个块被忽略 - fallback色(如
#2563eb)必须写在@supports块外部且上方,否则某些环境不加载OKLCH
暗色媒体查询必须后置,且不能和.dark类混用
@media (prefers-color-scheme: dark)要放在普通:root之后,否则层叠顺序导致变量覆盖失败。更关键的是:别在.dark类里重复定义整套OKLCH变量——这会和系统偏好冲突,且无法自动响应切换。
- 只在一个地方定义变量:
:root块中先声明占位值(哪怕只是oklch(50% 0 0)) - 暗色规则紧跟其后:
@media (prefers-color-scheme: dark) { :root { --text-default: oklch(12% 0.015 240); } } - 如果还要支持手动切换(比如用户点按钮强制切暗色),用JS加
data-theme="dark",再写[data-theme="dark"] { ... },但变量值仍需与媒体查询一致,避免两套逻辑打架
渐变和过渡必须全链路OKLCH,否则中间帧发灰
CSS的transition和linear-gradient不保留色彩空间语义。哪怕你定义了--primary: oklch(62% 0.28 258.5),只要:hover状态用了hsl()或rgb(),浏览器就会 fallback 到 sRGB 线性插值——动画过程不是按 OKLab 路径走,而是 RGB 三通道直插,中间必然失真、发灰。
- 悬停加深:用
oklch(65% 0.28 258.5)→oklch(70% 0.28 258.5),只调L - 禁用态:用
oklch(62% 0.12 258.5),只降C,不碰L,确保浅底上文字仍可读 - 渐变色相差>180°时必须拆段:
linear-gradient(to right, oklch(0.7 0.25 350), oklch(0.7 0.25 0), oklch(0.7 0.25 10))
@supports结构颠倒让OKLCH根本不加载、过渡/渐变混用色彩空间引发中间帧发灰。这些都不是“效果不好”,而是“根本没生效”——查起来特别费时间。


















