<p>hover颜色不变是因为仅用hsl(from var(--primary) h s l)未修改值,必须用calc()调整如calc(l - 12);HSL空间调亮度最可靠,RGB直接计算易偏色,oklch()更符合人眼但Safari不支持。</p>

直接用 hsl(from var(--primary) h s l) 写 hover 颜色,颜色不会变——因为没算任何东西,只是把原值重新拼回去。
为什么 hover 时颜色一动不动
常见错误是只写 color: hsl(from var(--primary) h s l),以为 from 本身就能“变暗”。实际它只是个解构操作:把 --primary 拆成 h、s、l 三个变量,但不改它们就等于没做任何事。
真正起作用的是 calc()。没有它,from 就是语法摆设。
-
hsl(from #3b82f6 h s l)→ 等价于hsl(210 75 48),完全静态 -
hsl(from #3b82f6 h s calc(l - 15))→ 才会把亮度从 48 降到 33,视觉上明显变深 - 浏览器报错或静默失效,往往是因为
calc()里写了单位(如l - 15%),HSL 的l和s是纯数字(0–100),不能带 %
hover 变深的推荐写法(HSL 空间)
HSL 最适合 UI 状态调节:色相(h)和饱和度(s)通常不动,只调亮度(l)。Chrome/Firefox/Safari 均已稳定支持(Chrome 111+、Firefox 119+、Safari 16.4+)。
立即学习“前端免费学习笔记(深入)”;
- 按钮背景悬停变深:
background: hsl(from var(--primary) h s calc(l - 12)) - 文字悬停变暗(更易读):
color: hsl(from var(--text) h s calc(l - 8)) - 禁用态降透明度 + 微调亮度:
color: hsl(from var(--primary) h s calc(l - 5) / 0.6)(注意 alpha 必须用/引入) - 避免
l超出 0–100 范围:比如原色l是 10,再减 15 就变成负数,部分浏览器会 clamp 到 0,但行为不统一,建议加@supports降级或预估安全范围
RGB 空间里调亮度?别这么做
RGB 没有“亮度通道”,r、g、b 是独立分量。直接写 rgb(from var(--primary) calc(r * 0.8) calc(g * 0.8) calc(b * 0.8)) 看似合理,但结果常偏色(比如蓝色变紫、红色发棕),且人眼感知亮度不线性。
- 想控制明暗,优先用
hsl()或oklch() -
oklch()的L(亮度)更符合人眼,但 Safari 当前不支持,必须配降级:@supports (color: oklch(0 0 0)) { ... } - 如果必须用 RGB(例如 legacy 系统),改用
color-mix()+black更稳妥:color-mix(in srgb, var(--primary), black 20%)
空格和斜杠细节,一错全挂
新版颜色函数对空格和分隔符极其敏感,写错一个字符就回退到初始色或透明。
- 正确:
rgb(255 0 0 / 0.7)(空格分隔数值,/引入 alpha) - 错误:
rgb(255, 0, 0, 0.7)、rgb(255 0 0 0.7)、rgb(255 0 0 /0.7)(/前后缺空格) -
from后必须紧跟颜色值或变量,不能换行或加注释:hsl(from /* comment */ var(--x) h s l)会解析失败 - 所有
calc()内部禁止单位:写calc(l - 10),不是calc(l - 10%);rgb()里写calc(r * 0.9),不是calc(r * 0.9)后面再跟%
真正难的不是写对语法,而是判断该在哪一层调参:是只降 l,还是同步压 s 避免过艳?要不要为深色模式单独定义 --primary-dark 变量?这些没法靠 from 自动推导,得结合设计系统手动校验。


















