contrast() 是 Less 编译期实现语义化高对比度文本生成的唯一内置函数,基于背景色明度自动选择 darken() 或 lighten() 后的安全色,参数顺序为 contrast(@background, @dark-base, @light-base, @threshold),阈值默认 0.43,旧版 Less(

contrast() 是 Less 编译期唯一能真正实现“语义化高对比度文本生成”的内置函数,不是滤镜、不依赖 JS、也不靠人眼调值。
contrast() 函数的正确调用方式
它不是简单反转颜色,而是基于背景色的 HSL 明度(luminance)做判断,自动选 darken() 或 lighten() 后的安全色。典型写法:
@bg: #2a2a2a; @text-on-bg: contrast(@bg, #000, #fff, 0.43); // 返回 #fff
参数顺序不能错:contrast(@background, @dark-base, @light-base, @threshold)。前两个是你的“深/浅文字基准”,后两个是明度阈值(默认 0.43,越小越倾向返回浅色)。
- 传入
transparent或未定义变量会直接报错Operation on an invalid type - 阈值设为
0.8会导致浅灰背景(如#f0f0f0)仍返回#000,实际对比度不足 - 旧版 Less(contrast(@bg, #000, #fff),阈值固定为 0.43
为什么 invert() 和手动取反都不行
invert() 是 CSS 运行时滤镜,lessc 编译时根本看不到它——你没法用它生成变量、没法链式调用 fade() 或 saturate(),更没法保证 WCAG AA/AAA 对比度。
-
invert(100%)对#888输出#777,视觉上几乎无变化 - RGB 取反(如
#rgb → #000)在中间灰阶完全失效,#aaa变成#555,对比度反而崩了 - 所有这些方案都绕开了“可读性”本质:人眼识别文字靠的是明度差,不是色相翻转
微调 contrast() 输出以兼顾可读性与视觉舒适度
contrast() 给的是安全底线色,但 UI 常需要更柔和的表达。比如背景是 #121212,它返回 #fff 没错,但 #e0e0e0 更耐看;背景是 #fafafa,它返回 #000,但 #333 更友好。
推荐组合写法:
@text-on-dark: lighten(contrast(#121212, #000, #fff), 5%); @text-on-light: darken(contrast(#fafafa, #000, #fff), 10%);
- 只用
lighten()或darken()调整亮度,避免spin()改色相——文字不需要偏蓝或泛黄 - 调整幅度建议控制在 3%–10%,超过 15% 容易跌破 WCAG AA(4.5:1)最低标准
- 别对
contrast()结果再套一层contrast(),这没有意义,编译器不会递归优化
检查和兼容性兜底必须做
项目上线前漏掉版本检查,轻则编译失败,重则主题色全黑或全白。
- 运行
lessc --version确认 >= 3.5;若用less-loader,查它封装的 Less 版本,不是 Webpack 版本 - Webpack 项目中,
less-loader默认可能绑着老版本 Less,需显式指定less依赖版本并resolutions锁死 - 低于 Less 3.0 的环境,
contrast()直接不可用,得退到lighten(@bg, 60%)+ 手动测试对比度
真正麻烦的不是写法,而是很多人把 contrast() 当成“自动变色开关”,却忘了它输出的是一个静态色值——一旦背景色动态变化(比如 JS 切 theme),就得换运行时方案,Less 本身管不了这个。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











