应避免用 lightness() 判断文字色,因其不等同 WCAG 相对亮度,浅黄、淡紫等色相下易出错;须用 luminance 或完整 WCAG 对比度公式验证,且编译期函数无法处理 CSS 变量或运行时颜色。

直接用 lightness() 判断明暗再选黑白,大概率不达标——它不等于 WCAG 相对亮度,浅黄、淡紫等色相下会给出错误文字色。
别信 lightness(),它不是 WCAG 亮度
很多人写 @if lightness($bg) ,结果 #ffcc00(浅黄)被当“暗色”配白字,实际对比度仅 ~1.8,完全不可读。原因:HSL 的 L 值是几何平均,没做 sRGB gamma 校正和人眼加权。WCAG 要求的是相对亮度 <code>L = 0.2126×R + 0.7152×G + 0.0722×B,其中 R/G/B 已按 pow((c+0.055)/1.055, 2.4) 非线性转换。
-
lightness(#ffcc00)≈ 60 → 误判为“够亮”,该用黑字;但真实relative-luminance(#ffcc00)≈ 0.72,配黑字对比度仅 ~1.8 - 必须用
relative-luminance()+contrast-ratio()显式计算,而不是依赖视觉直觉或 HSL 分量 - Dart Sass ≥1.70 才支持
sass:math,旧版用pow()会精度崩坏,建议统一升级
用 contrast-ratio() 显式判断白/黑字是否合格
核心逻辑不是“背景够不够暗”,而是“白字和背景的对比度 ≥ 4.5”或“黑字和背景的对比度 ≥ 4.5”。SCSS 里不能动态 fallback,所以得提前算清哪个可用。
- 先定义
relative-luminance($color):对每个通道做分段处理(时线性,否则幂运算),再加权 - 再封装
contrast-ratio($a, $b):取两色亮度最大/最小值,套公式(L_max + 0.05) / (L_min + 0.05) - 最终函数返回颜色值,不是布尔:
@return if(contrast-ratio($bg, #fff) >= 4.5, #fff, #000) - 注意:传入带 alpha 的颜色(如
rgba(51,51,51,0.8))会出错,必须先用mix()合成到目标背景上再算
别在 @each 循环里反复调用对比度函数
编译期虽不报错,但调试时根本看不出哪次调用导致了错误文字色——比如某主题色 $theme-warning: #f39c12,函数返回 #fff,但实际和白字对比度只有 4.2,不达标。
立即学习“前端免费学习笔记(深入)”;
- 更稳妥的做法是:把所有主题色对应的文字色提前算好,声明为独立变量,例如
$text-warning: #000 - 这样既能人工复核(打开浏览器 DevTools 看真实渲染色+对比度),也方便后续覆盖:
$text-warning: #2c3e50直接生效 - 如果真要用函数,确保只在变量赋值处调用一次,不要嵌套进选择器生成逻辑中
- Font Awesome 7 的
fa-color-contrast()可直接复用,但它内部也只做了 luminance 阈值判断(≈40%),未完整走 WCAG 对比度公式,仍需验证
真正容易被忽略的是:SCSS 函数只能处理编译期已知的颜色值,一旦颜色来自 CSS 变量(var(--bg))或运行时 JS 注入,整套逻辑就失效——这时候必须切到 JS 或原生 CSS 方案(color-contrast() + @property)。


















