Sass mix 颜色混合函数用法
什么是 mix
Mix 函数是将两种颜色根据一定的比例混合在一起,生成另一种颜色。
语法:mix($color-1,$color-2,$weight)
$color-1和$color-2指的是你需要合并的颜色,颜色可以是任何表达式,也可以是颜色变量。$weight为 合并的比例(选择权重),默认值为50%,其取值范围是0~1之间。它是每个RGB的百分比来衡量,当然透明度也会有一定的权重。默认的比例是 50%,这意味着两个颜色各占一半,如果指定的比例是25%,这意味着第一个颜色所占比例为25%,第二个颜色所占比例为75%。
实际用法
$primary: #409eff;
.demo {
// 各占一半
color: mix($primary, #fff); // #a0ceff
// 第一个色占 20%,白色占 80% —— 得到很浅的底色
background: mix($primary, #fff, 20%);
// 混黑色变深,做 hover 态
border-color: mix($primary, #000, 80%);
}
编译后:
.demo {
color: #a0ceff;
background: #ecf5ff;
border-color: #337ecc;
}
$weight 写 20% 和写 0.2 是等价的,Sass 内部都归一化处理。我习惯写百分比,因为「第一个颜色占多少」这个语义更直白。
混合是怎么算的
不考虑透明度时就是逐通道的线性插值:结果通道 = 通道1 × w + 通道2 × (1 - w)。拿上面 mix($primary, #fff, 20%) 验算一下,#409eff 是 rgb(64, 158, 255),#fff 是 rgb(255, 255, 255):
- R:
64 × 0.2 + 255 × 0.8 = 12.8 + 204 = 216.8 ≈ 217 = 0xEC - G:
158 × 0.2 + 255 × 0.8 = 31.6 + 204 = 235.6 ≈ 236 = 0xEC(进位取整) - B:
255 × 0.2 + 255 × 0.8 = 255 = 0xFF
对上了 #ecf5ff。注意这个插值是在 sRGB 空间直接做的,不做 gamma 校正,所以混合结果在感知上不一定「正好在中间」——两个饱和度高的对比色混出来常常偏灰偏暗。这不是 Sass 的 bug,是 sRGB 线性插值的固有特性。
透明度参与时权重会变
原文说「透明度也会有一定的权重」,这句需要展开,因为它是 mix 最容易算错的地方。当两个颜色的 alpha 不同时,$weight 不再是直接的 RGB 混合比例,Sass 会先用 alpha 差值调整实际的混合权重。规则来自 SCSS 的实现:设归一化后的权重为 w,alpha 差为 a = alpha1 - alpha2,则
w1 = ((w × 2 - 1) × (w × a == -1 ? w × 2 - 1 : ((w × 2 - 1) + a) / (1 + (w × 2 - 1) × a)) + 1) / 2w2 = 1 - w1
结果的 alpha 则始终是按原始 $weight 做的直接插值:alpha = alpha1 × w + alpha2 × (1 - w)。
实用结论是:和半透明色混合时不要靠心算预期结果,直接编译出来看。要做「同一个色加透明度」这件事,rgba($primary, 0.2) 或 color.change($primary, $alpha: 0.2) 比 mix 更合适。
模块化后的写法
Sass 从 1.23 开始推动 @use 模块系统,全局函数逐步被废弃。mix 现在的正式身份是 color 模块的成员:
@use 'sass:color';
.demo {
// 新写法
background: color.mix(#409eff, #fff, 20%);
}
全局的 mix() 目前还能用(Dart Sass 尚未移除),但已标记为废弃,新项目建议直接用 color.mix。同一模块下配套的还有几个我常用的:
@use 'sass:color';
$c: #409eff;
.demo {
// 调亮/调暗(本质是改 HSL 的亮度)
a: color.scale($c, $lightness: 20%);
// 调整饱和度
b: color.adjust($c, $saturation: -30%);
// 直接替换某个通道
c: color.change($c, $alpha: 0.5);
// 取反色
d: color.invert($c);
// 读通道值
e: color.red($c); // 64
f: color.lightness($c); // 62.5490196078%
}
scale 和 adjust 的区别值得记一下:adjust 是绝对加减,lightness: 20% 就是亮度直接 +20;scale 是按剩余空间的比例缩放,lightness: 20% 意思是往 100% 的方向走剩余距离的 20%。做主题色的明暗变体用 scale 更安全,因为它永远不会溢出边界(不会出现加到 120% 被截断成纯白的情况)。
老代码里常见的 lighten() / darken() / saturate() / desaturate() 都等价于 adjust 的单参数形式,同样在废弃路径上。
典型用途:生成主题色阶
Element Plus 那套颜色体系就是用 mix 混白/混黑生成的,这个套路很实用:
@use 'sass:color';
$primary: #409eff;
:root {
// 浅色阶:和白色混,权重递减
@for $i from 1 through 9 {
--color-primary-light-#{$i}: #{color.mix($primary, #fff, (10 - $i) * 10%)};
}
// 深色阶:和黑色混
--color-primary-dark-2: #{color.mix($primary, #000, 80%)};
}
比手写一堆十六进制值好维护得多,改一个 $primary 整套色阶跟着走。需要注意 #{} 插值是必须的,因为在自定义属性里 Sass 不会自动求值——--x: color.mix(...) 会被原样输出成字符串,浏览器解析不了。

还没有留言,来发表第一条吧~