必须只调lightness,因人眼对明暗最敏感,固定--h和--s可确保所有颜色落在同一视觉灰阶轴上,不跳色、不偏紫、对比度可控;动hue或saturation易致泛粉、失色或断链,且Safari≤15.4会静默忽略hsl()内calc()计算。
只调 lightness,固定 --h 和 --s,才能生成真正可用、可维护、不发灰的同色系配色;其他任何组合(比如动 saturation 或混用 calc() 在 hsl() 里算明度)都会在 Safari ≤15.4 静默失效,或导致对比度崩坏、换色时整套变量失联。
人眼对明暗最敏感。同一 --h 和 --s 下只调 lightness,所有颜色落在一条视觉连贯的“灰阶轴”上:不跳色、不偏紫、文字对比度可控。一旦同时改 saturation,比如悬停写成 hsl(calc(var(--h) + 5), calc(var(--s) - 10%), var(--l)),高饱和蓝会突然泛粉,浅背景上文字直接不可读。
常见问题表现:
--color-primary-300 是 #c2e9ff,--color-primary-700 是 #0288d1,但换主色后发现两者根本不在同一色相环上——因为它们是手动挑的,不是从同一基础色派生color: hsl(200, 70, 60)(缺 %)→ 整条声明被忽略,浏览器不报错也不提示hsl(0, 70%, 60%) 和 hsl(360, 70%, 60%) 混用 → CSS 解析视为不同值,变量计算可能异常Safari ≤15.4(含 iOS 15.4)会静默忽略 hsl(var(--h), var(--s), calc(var(--l) + 10%)) 这类写法,整条样式失效,回退到继承色或透明——你根本看不到问题在哪。
正确做法是把计算结果提前固化为独立变量:
:root 里定义:--l-primary-dark: 40%、--l-primary-light: 85%
background-color: hsl(var(--h-primary), var(--s-primary), var(--l-primary-dark));
calc(var(--l-base) - 25%),但下限卡死 15%
calc(var(--l-base) + 30%),上限封顶 92%
lightness 不是随便拉滑块的参数,它直接影响可访问性和渲染表现:
12%:高饱和蓝/绿容易失色,看起来像黑灰,尤其在 OLED 屏上92%:泛白、刺眼,WCAG 文本对比度常跌破 4.5:115%–92%;主色建议落在 40%–70% 之间,留出上下调节余量lightness,容易发灰,建议同步把 saturation 降到 20%–30%
真正难的不是写对一行 hsl(),而是所有衍生色都得从同一个 --h 和 --s 出发;一旦某个组件偷偷改了饱和度,整套色系就断链了——这种断裂在深色模式切换或品牌色更新时才会暴露,但修复成本远高于初期规范。