OKLCH 与广色域:为什么你的颜色在别人的屏幕上不一样

一篇讲透现代 CSS 颜色:sRGB 的历史包袱、OKLCH 的 L/C/H 三分量为什么对感知更均匀、display-p3 能多出哪些颜色、@media (color-gamut) 的回落写法、等感知明度色阶怎么做,以及检查颜色是否超出目标色域的完整流程。

约 7 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证

sRGB 是 1996 年的显示器,不是颜色的全部

HEX 和 rgb() 描述的是 sRGB 色域里的点——1996 年为 CRT 定的标准,只覆盖人眼可见范围的一小部分。现代手机与显示器普遍支持 display-p3,饱和的红绿青比 sRGB 多出近三分之一。你写的 #22c55e 在 p3 屏幕上被硬映射,在别的设备上就显得不一样;而 OKLCH 把「颜色」与「设备能力」解耦:L 明度、C 色度、H 色相都按人眼感知均匀刻度。

分量含义比 HEX 好在哪
L 明度 0–100%感知明度,L 相同的两个颜色看起来一样亮等明度色阶终于「真的等明度」,HEX 做不到
C 色度 0–0.4+饱和度,但沿感知刻度降饱和不再顺带变亮/变暗
H 色相 0–360色环位置,与 sRGB 色相角不同蓝紫方向不会再「转一下就变色」

广色域写法与回落

CSS Color 4 的正确姿势:@supports 里写 p3 增强,外层保留 sRGB 回落;再用 color-gamut 媒体查询判断设备能力。色值超出目标色域时浏览器会裁剪(gamut mapping),但主动控制比被动裁剪可控得多。

回落 + 增强:两行都写
.brand {
  color: oklch(64% 0.2 262);                        /* 全浏览器:OKLCH 语法 */
}
@media (color-gamut: p3) {
  .brand { color: oklch(64% 0.28 262); }            /* p3 屏:更高色度 */
}
/* 极老浏览器连 oklch() 都不认 → 再补一行 hex 放最前 */
等感知色阶:只动 L,其他不动
--brand-50:  oklch(97% 0.03 262);
--brand-500: oklch(64% 0.21 262);
--brand-900: oklch(32% 0.12 262);
/* L 从 97 线性降到 32,视觉上每级亮度差一致。
   用 HEX 手调的 #eef→#123 色阶明度忽高忽低。 */

排查清单:颜色不对劲时看哪里

  1. 确认设计稿色值的色彩空间:Figma 导出的 sRGB hex 到 p3 设计稿里直接用会偏差
  2. 用转换工具看目标色是否溢出 sRGB——溢出的颜色在普通屏幕上必然「缩水」,要准备回落值
  3. 检查对比度:广色域提饱和后白字可能不达标,WCAG 4.5:1 重新验一遍
  4. 同一品牌色在暗色模式下重调 L/C,而不是直接复用亮色值
  5. 截图对比不同设备时关掉系统的「鲜艳/自然」显示模式,排除系统级色差干扰

常见问题

oklch() 浏览器支持如何?

2023 年起全绿:Chrome 111、Safari 15(部分 16.4)、Firefox 113。2023 年之前的浏览器会丢弃整条声明,所以把回落 hex 写在前面仍然是标准做法。

OKLCH 和 HSL 有什么本质区别?

HSL 的「明度」不是感知明度:hsl(60 100% 50%) 的黄色看起来远比 hsl(240 100% 50%) 的蓝亮,调 L=50% 得到的颜色亮度天差地别。OKLCH 的 L 是按人眼响应标定的,L 相同等亮——这就是 Tailwind v4、iOS、Figma 都转向 OKLCH/OKLab 的原因。

色度写多大会溢出?

取决于色相:绿青方向 sRGB 大约 0.15+ 就出界,红紫方向能到 0.25+。别背表——用转换工具的色域标尺看实时判定,溢出时会给出 sRGB 内最接近的可视替代。

📂

松开以自动格式化

支持 .json / .sql / .csv / .html / .css / .xml / .yaml 文件