纯 css 中没有 darken() 或 lighten() 函数,必须用 hsl() + calc() 手动调整 l 值,或使用现代 color-mix();不可用 opacity/filter/蒙层模拟,也不能通过 css 变量自动推导色阶。

纯 CSS 里没有 darken() 或 lighten() 函数,硬写会直接失效或被忽略——这不是兼容性问题,而是语法根本不存在。
用 hsl() + calc() 手动调 L 值
这是目前最通用、浏览器支持最广的方案,本质是把颜色预先拆成 HSL 分量,再对亮度(L)做算术运算。
-
--base-h和--base-s必须存为无单位数值(如210、80),不能带%或deg单位;--base-l同样用整数(如60),而非60% -
calc(var(--base-l) - 15)才合法;写成calc(var(--base-l) - 15%)会报错,因为calc()不允许混合单位 - L 值必须手动截断:超出
0–100范围时,浏览器不会报错但渲染不可控(比如calc(5 - 15)→-10→ 实际取0,颜色发灰);可用max(0, min(100, ...))包裹 - 最终拼接时,
hsl()的 S 参数需补%单位:hsl(var(--base-h), calc(var(--base-s) * 1%), var(--dark-l))
用 color-mix() 混合黑白(现代浏览器)
color-mix() 是 CSS Color Level 4 新特性,在 Chrome 111+、Firefox 117+、Safari 16.4+ 可用,语义更直观,但行为与 Sass 不同。
- 它在
srgb空间线性插值,不是 HSL 亮度通道调整,对深色“提暗”更柔和,不易突变发黑 - 写法简洁:
--dark-color: color-mix(in srgb, var(--base-color), #000 15%)表示加 15% 黑色 - 不依赖 H/S/L 拆解,基础色可用
#3498db、rgb()或hsl()任意格式 - 注意:它不等价于
darken($color, 15%),尤其对高饱和色,结果偏灰而非保色相
避免用透明层或滤镜“模拟”明暗
像 opacity: 0.8、filter: brightness(0.8) 或叠加 rgba(0,0,0,0.2) 蒙层,看似简单,但实际偏离了 darken/lighten 的设计意图。
-
opacity会同时降低所有通道和 alpha,破坏可访问性对比度,且无法单独控制亮度 -
brightness()是设备相关滤镜,不同显示器渲染差异大,WCAG 对比度校验不可靠 - 蒙层方案在多层叠加时容易产生意外色彩偏差(尤其半透叠加多次),维护成本高
- 这些方法无法生成独立颜色变量,没法用于 border、text-shadow 等需要纯色值的场景
别指望 CSS 自定义属性自动推导色阶
你不能写 --primary-dark: darken(var(--primary), 10%) —— 浏览器连语法解析都不会通过。CSS 变量是运行时机制,而 darken 是 Sass 编译期函数,二者执行阶段完全隔离。
- 所有“推导色”都必须显式声明,要么靠
hsl()+calc()静态计算,要么靠 JS 动态生成并注入 - 如果要响应系统深色模式,得用
@media (prefers-color-scheme: dark)切换整套 HSL 变量,而不是指望一个变量自动适配 - 真正难的不是怎么写,而是调完之后——用 DevTools 的无障碍面板检查文字对比度是否仍满足 WCAG AA(≥ 4.5:1),这点 Sass 和 CSS 都不会提醒你
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











