必须只调L、固定C和H,否则视觉灰阶断裂;因L是CIE明度(0%=黑,100%=白),感知线性,同H/C下调L可确保不偏色、不发灰、对比度可控,而动C或H易致泛白、banding或跳色。

只调 L,固定 C 和 H,否则视觉灰阶就断了——这是用 lch() 提升感知一致性的唯一可靠路径。
为什么 lch() 的 L 值调明暗更准
lch() 的 L 是 CIE Lightness(0% = 黑,100% = 白),它模拟人眼对明暗的非线性响应,不是 RGB 的数值缩放,也不是 HSL 的数学平均。同一 H 和 C 下改 L,所有色块落在一条视觉灰阶轴上:不偏色、不发灰、对比度可预期。
常见错误现象:lch(60% 90 240) → lch(40% 110 240) 看起来深色变体突然泛白、边缘带灰晕,尤其在 OLED 屏上出现 banding;这是因为动了 C,实际彩度超出了当前亮度下屏幕可忠实还原的范围。
-
L在 15%–92% 区间较安全:低于 15% 高彩度蓝/绿会塌成黑灰,高于 92% 易泛白刺眼 -
C不是越大越好:LCD 屏在L: 50–70时C > 110就开始 banding;OLED 可试到 130,但必须真机验 -
H值循环安全:360° 和 0° 等价,但跨色相插值(如蓝→黄)不能靠calc(var(--h) + 30)线性加减,会经过不可控灰带
写错单位整条声明就消失
lch() 不报错、不警告、不降级——它直接跳过整行 CSS。设计师或构建脚本输出的值若单位不对,UI 就会“消失”:背景透明、文字继承父级色、按钮变不可见。
立即学习“前端免费学习笔记(深入)”;
常见失效写法:
-
lch(70 80 240deg)——L缺%(必须是70%或0.7) -
lch(70% 80% 240deg)——C多写了%(C是无量纲数值,80合法,80%非法) -
lch(70% 80 240)——H缺deg(必须显式写240deg) -
lch(0% 100 240deg)——L=0%或100%时C强制归零,渲染为纯黑/纯白,不是“暗蓝”或“亮紫”
兼容性陷阱与 fallback 必须前置
lch() 在 Chrome 111+、Safari 16.4+、Firefox 123+ 支持,但旧版 Safari(如 15.x)会直接忽略整条声明,不是变灰,是“消失”。安卓 WebView 基本不支持,@supports (color: lch(0% 0 0)) 在多数 WebView 中返回 false。
关键实操原则:
- fallback 必须写在
lch()声明**之前**,CSS 后声明覆盖前声明,且不支持条件判断 - 不能用 CSS 变量存原始
lch()值:--main: lch(60% 50 210);浏览器读不懂,变量无效 - 推荐结构:
color: hsl(210, 70%, 50%); color: lch(62% 52 210); -
@supports检测仅用于增强场景,**不能用于关键颜色切换逻辑**——部分 Safari 版本误报,且安卓 WebView 存在解析 bug
transition 不走 LCH 插值,别被语法骗了
即使你写了 background-color: lch(60% 80 240); transition: background-color 1s;,浏览器动画仍默认在 sRGB 空间插值,中间帧会发灰、跳色、偏紫——这不是你写错了,是 CSS 动画机制本身的限制。
验证方式:用 DevTools 拾色器拖动时间轴,观察中间帧 RGB 值是否呈线性变化(是)→ 说明没走 LCH。
- 真正能触发 LCH 插值的只有:
color-mix(in lch, ...)、@property控制的自定义变量、以及linear-gradient(in lch, ...) -
linear-gradient(in lch, ...)是目前唯一原生支持 LCH 插值的 CSS 特性,但它只适用于渐变,不适用于单色背景或边框动画 - 做 hover 明暗变化时,只动
L:lch(52% 52 210)→lch(42% 52 210),保持C和H不变
最常被忽略的一点:DevTools 不显示真实 lch() 值,复制出来的永远是降级后的 sRGB 十六进制;想确认是否生效,只能肉眼比对——比如和已知可靠的 #3a50e0 并排看。调试时别信面板里那个十六进制值,它只是幻影。


















