你以为 Sass 的颜色函数无可替代?今天 CSS color-mix() 把这件事彻底原生化了
三年前,团队里每个人都在说「换主题色很简单,变量改一行就行」。结果你发现,hover 态、active 态、disabled 态、边框色、背景色、阴影色全是一个个硬编码的 hex,每改一次主题色要改十几个地方。
这不是变量没定义好,是颜色派生的逻辑从来没被抽象过。
今天这件事被 CSS color-mix() 和相对颜色语法彻底原生化了。
color-mix():两个颜色,一行搞定
color-mix() 的用法非常直接:
/* 80% 主色 + 20% 白色 = 更亮的 hover 态 */
.button:hover {
background: color-mix(in oklch, var(--brand) 80%, white);
}
/* 80% 主色 + 20% 黑色 = 更暗的 active 态 */
.button:active {
background: color-mix(in oklch, var(--brand) 80%, black);
}
这里最关键的选择是颜色空间。用 srgb 混出来的紫色是「泥巴紫」,用 oklch 混出来的才是「干净紫」。生产环境一律用 oklch,感官上更符合直觉。
相对颜色语法:只改一个变量,全套派生自动更新
color-mix() 是两个颜色之间的混合。但更多时候你需要的是「在这个颜色的基础上,调亮一点、调暗一点、降低饱和度」。这就要用相对颜色语法:
@property --brand {
syntax: "<color>";
inherits: true;
initial-value: #4f46e5;
}
/* 主色派生:亮度 +8% */
.card-hover {
background: oklch(from var(--brand) calc(l + 0.08) c h);
}
/* 主色派生:饱和度砍一半 */
.card-muted {
background: oklch(from var(--brand) l calc(c * 0.5) h);
}
/* 主色派生:色相旋转 180°,得到互补色 */
.card-complementary {
background: oklch(from var(--brand) l c calc(h + 180));
}
所有派生颜色都挂在 –brand 这一个变量上。设计师哪天说「换个品牌色」,你只改一行:
:root {
--brand: #10b981;
}
所有派生色全部自动更新,不需要 build step,不需要 Sass,不需要 JavaScript。
实际设计系统里的用法
一个常见的设计系统 token 结构:
:root {
--primary-500: #4f46e5;
--primary-50: color-mix(in oklch, var(--primary-500) 8%, white);
--primary-100: color-mix(in oklch, var(--primary-500) 16%, white);
--primary-200: color-mix(in oklch, var(--primary-500) 32%, white);
--primary-300: color-mix(in oklch, var(--primary-500) 50%, white);
--primary-400: color-mix(in oklch, var(--primary-500) 70%, white);
--primary-600: color-mix(in oklch, var(--primary-500) 70%, black);
--primary-700: color-mix(in oklch, var(--primary-500) 85%, black);
--primary-900: color-mix(in oklch, var(--primary-500) 97%, black);
}
浏览器支持
color-mix() 自 2023 年 5 月起已纳入 Baseline Widely Available,Chrome 111+、Firefox 113+、Safari 16.2+、Edge 111+ 全球覆盖率超过 92%,生产环境直接用,不需要任何 polyfill。
相对颜色语法稍微新一点,Chrome 119+、Firefox 128+、Safari 16.4+,Firefox 150 之前版本有微小差异,建议加一个 @supports 渐进增强:
.button {
background: #4f46e5;
background: oklch(from var(--brand) calc(l + 0.08) c h);
}
什么时候还是需要 Sass
color-mix() 和相对颜色语法解决的是运行时颜色派生的问题。但 Sass 的 lighten()、darken() 这类函数解决的是「构建时色板生成」,对于需要在编译阶段输出固定 hex 值的场景(比如 CSS-in-JS 静态提取),Sass 仍有价值。
简单判断:如果你在设计系统里定义的是「关系」而不是「具体值」,CSS 颜色函数已经完全够用。
三步下一步
第一步: 把现有设计系统里的硬编码派生色替换成 color-mix(),从主色变量开始,一层层派生。
第二步: 把 Sass 的 color 函数调用迁移到 oklch(from) 相对颜色语法,把派生关系写成「公式」而不是「查表值」。
第三步: 如果你用 CSS-in-JS,确认你的环境支持 @property 注册自定义属性,这是让颜色变量参与过渡动画的前提。
一个主色变量管全套的时代,今天正式开始了。
评论区
登录后可评论。