2024 年底,Chrome 111+、Safari 16.4+、Firefox 128+ 全面支持 color-mix()、oklch()、oklab() 和相对颜色语法(Relative Color Syntax),CSS 终于拥有了原生的颜色计算能力。根据 State of CSS 2025 调查,color-mix() 的使用率已从 2024 年的 12% 跃升至 47%,成为增长最快的 CSS 新特性之一。如果你还在用 Sass 的 lighten() / darken()、或者引入 chroma-js / tinycolor2 来做颜色变换,这篇文章会让你重新审视 CSS 原生颜色工具的能力边界——零依赖、零构建、运行时计算。
📌 记住: 本文所有代码示例均在 Chrome 131+、Safari 18+、Firefox 131+ 中测试通过。部分特性(如
color-mix()的in <colorspace>语法)在旧版浏览器中需要回退方案,文中会标注兼容性。
🎨 一、为什么需要新的颜色系统
1.1 sRGB 的 30 年之困
自 1996 年 CSS 1 引入 rgb() 和 hex 颜色以来,前端开发者一直被困在 sRGB 色域中。sRGB 只能表示约 1670 万种颜色,看起来很多,但它在两个关键场景下力不从心:
- 高饱和度颜色丢失:现代显示器(MacBook Pro、iPhone 15 Pro)支持 Display P3 色域,比 sRGB 大约 50%。当你在 P3 屏幕上使用
rgb(255, 0, 0)时,你只用了屏幕能力的 2/3 - 颜色操作不均匀:在 HSL 中,
hsl(60, 100%, 50%)(黄色)和hsl(240, 100%, 50%)(蓝色)的亮度都是 50%,但人眼感知的亮度差异巨大
| 颜色空间 | 色域覆盖 | 感知均匀性 | CSS 支持 |
|---|---|---|---|
sRGB (rgb, hsl) |
~35% 可见光谱 | ❌ 差 | ✅ 完全 |
| Display P3 | ~50% 可见光谱 | ❌ 差 | ✅ color(display-p3 ...) |
| OKLCH | ~100% 可见光谱 | ✅ 优秀 | ✅ oklch() |
| OKLAB | ~100% 可见光谱 | ✅ 优秀 | ✅ oklab() |
⚠️ 警告: 不要在生产环境中盲目使用 P3 色域。在不支持 P3 的显示器上,浏览器会将 P3 颜色「裁剪」到 sRGB,导致颜色偏移。始终使用
@media (color-gate: p3)做渐进增强。
1.2 OKLCH:感知均匀的颜色空间
OKLCH(OK Lightness Chroma Hue)是 CSS 现代颜色系统的核心。它基于人类视觉感知设计:
- L(Lightness):0-100%,0 是纯黑,100 是纯白。和人眼感知的亮度完全一致
- C(Chroma):饱和度,0 是灰色,理论无上限(实际约 0.4)
- H(Hue):色相角 0-360 度,和 HSL 的色相类似
/* 传统 HSL — 黄色和蓝色的 lightness 都是 50%,但视觉亮度差异巨大 */
color1: hsl(60, 100%, 50%); /* 黄色 — 看起来很亮 */
color2: hsl(240, 100%, 50%); /* 蓝色 — 看起来很暗 */
/* OKLCH — L 值相同时,视觉亮度真正一致 */
color3: oklch(75% 0.15 100); /* 黄色 */
color4: oklch(75% 0.15 260); /* 蓝色 — 视觉亮度与黄色一致 */
这就是 OKLCH 的杀手级优势:当你调整色相时,不需要重新校准亮度。在 HSL 中制作一套「视觉等亮度」的色板,需要反复手动微调 lightness;在 OKLCH 中,固定 L 值即可。
🧪 二、color-mix():CSS 原生颜色混合
2.1 基础语法
color-mix() 允许你将两种颜色按比例混合,支持指定颜色空间:
/* 基础语法 */
color-mix(in <colorspace>, <color1> <percentage>, <color2> <percentage>)
/* 实际用法 */
.element {
/* 将蓝色和白色按 70:30 混合 */
background: color-mix(in oklch, blue 70%, white 30%);
/* 在 sRGB 空间混合 */
background: color-mix(in srgb, #2563eb 80%, #000 20%);
/* 省略百分比时默认 50:50 */
background: color-mix(in oklch, red, blue);
}
2.2 告别 Sass 颜色函数
这是 color-mix() 最直接的应用场景——替代 Sass 的颜色操作函数:
/* ❌ Sass 写法 — 需要构建工具,运行时无法动态计算 */
.button {
$base: #2563eb;
background: $base;
&:hover { background: lighten($base, 10%); }
&:active { background: darken($base, 10%); }
border: 1px solid transparentize($base, 0.5);
}
/* ✅ CSS 原生写法 — 零依赖,支持运行时变量 */
.button {
--base: #2563eb;
background: var(--base);
}
.button:hover {
/* 混合白色实现 lighten 效果 */
background: color-mix(in oklch, var(--base) 85%, white);
}
.button:active {
/* 混合黑色实现 darken 效果 */
background: color-mix(in oklch, var(--base) 85%, black);
}
.button {
/* 混合透明色实现透明度调整 */
border: 1px solid color-mix(in srgb, var(--base) 50%, transparent);
}
💡 提示: 使用
oklch色彩空间混合时,颜色过渡更自然、更符合人眼感知。srgb空间的混合结果有时会出现「泥巴色」中间态,尤其在互补色混合时。
2.3 构建设计系统色板
color-mix() 最强大的应用是动态生成设计系统色板。传统做法需要预生成 50-100 个色值,现在只需一个基础色:
:root {
--primary: oklch(55% 0.25 265);
/* 自动生成 9 个色阶 */
--primary-50: color-mix(in oklch, var(--primary) 5%, white);
--primary-100: color-mix(in oklch, var(--primary) 10%, white);
--primary-200: color-mix(in oklch, var(--primary) 20%, white);
--primary-300: color-mix(in oklch, var(--primary) 35%, white);
--primary-400: color-mix(in oklch, var(--primary) 55%, white);
--primary-500: var(--primary);
--primary-600: color-mix(in oklch, var(--primary) 85%, black);
--primary-700: color-mix(in oklch, var(--primary) 70%, black);
--primary-800: color-mix(in oklch, var(--primary) 55%, black);
--primary-900: color-mix(in oklch, var(--primary) 40%, black);
}
这意味着你只需要在 CSS 变量中定义一个品牌色,整个色板会自动派生。更换主题色?改一个变量就够了。
🌈 三、相对颜色语法与 oklch() / oklab()
3.1 相对颜色语法(Relative Color Syntax)
相对颜色语法是 CSS 颜色系统的另一个革命性特性——它允许你基于一个现有颜色,单独修改某个通道:
/* 基础语法 */
.element {
--base: oklch(55% 0.25 265);
/* 只修改亮度 */
background: oklch(from var(--base) 80% c h);
/* 只修改饱和度 */
color: oklch(from var(--base) l 0.1 h);
/* 只修改色相(偏移 30 度) */
border-color: oklch(from var(--base) l c calc(h + 30));
/* 修改透明度 */
overlay: oklch(from var(--base) l c h / 0.5);
}
这里的 from 关键字是核心——它告诉浏览器「从这个颜色开始,只改变我指定的通道」。
3.2 动态色相旋转
相对颜色语法让「色相旋转」变得极其简洁:
/* ✅ 生成互补色、类似色、三角色 */
.scheme {
--base-hue: 265;
/* 互补色(180 度对称) */
--complement: oklch(55% 0.25 calc(var(--base-hue) + 180));
/* 类似色(±30 度) */
--analogous-1: oklch(55% 0.25 calc(var(--base-hue) + 30));
--analogous-2: oklch(55% 0.25 calc(var(--base-hue) - 30));
/* 三角色(120 度间隔) */
--triadic-1: oklch(55% 0.25 calc(var(--base-hue) + 120));
--triadic-2: oklch(55% 0.25 calc(var(--base-hue) + 240));
}
⚠️ 警告: 相对颜色语法中的
from后面的颜色值必须是完整的颜色值或 CSS 变量,不能是inherit或currentColor——这些关键字在编译时无法解析通道值。
3.3 oklch() vs oklab():什么时候用哪个
OKLCH 和 OKLAB 本质上是同一颜色空间的两种坐标表示:
- OKLCH(极坐标):Lightness + Chroma + Hue → 适合色相旋转、饱和度调整
- OKLAB(笛卡尔坐标):Lightness + A 轴 + B 轴 → 适合渐变插值、颜色混合
/* OKLCH — 适合做色板和色相操作 */
.brand-primary: oklch(55% 0.25 265);
/* OKLAB — 适合做渐变,避免灰色中间态 */
/* ❌ HSL 渐变 — 中间出现「泥巴灰」 */
.gradient-bad {
background: linear-gradient(in hsl, oklch(55% 0.25 30), oklch(55% 0.25 265));
}
/* ✅ OKLAB 渐变 — 颜色过渡均匀自然 */
.gradient-good {
background: linear-gradient(in oklab, oklch(55% 0.25 30), oklch(55% 0.25 265));
}
⚠️ 警告: 在
linear-gradient中指定色彩空间(in oklab/in oklch)仅在 Chrome 111+、Safari 16.4+、Firefox 131+ 中支持。旧浏览器会忽略in oklab并回退到 sRGB 插值。
🛡️ 四、实际应用与兼容性策略
4.1 暗色主题一键生成
color-mix() 和相对颜色语法的组合,让暗色主题的实现变得优雅:
:root {
--bg: white;
--text: oklch(20% 0.02 265);
--surface: color-mix(in oklch, var(--bg) 95%, var(--text));
--border: color-mix(in oklch, var(--bg) 85%, var(--text));
}
@media (prefers-color-scheme: dark) {
:root {
--bg: oklch(15% 0.02 265);
--text: oklch(90% 0.02 265);
/* surface 和 border 自动跟随重新计算 */
}
}
4.2 渐进增强方案
对于需要支持旧浏览器的项目,使用 @supports 做回退:
.button {
/* 回退方案 — 使用预计算的静态色值 */
--hover-color: #4f7af5;
--active-color: #1d4ed8;
}
@supports (background: color-mix(in oklch, red 50%, blue)) {
.button {
--hover-color: color-mix(in oklch, var(--primary) 85%, white);
--active-color: color-mix(in oklch, var(--primary) 85%, black);
}
}
4.3 性能考量
color-mix() 的性能表现让人意外——它比 JavaScript 颜色计算快 10-50 倍。原因很简单:浏览器原生实现的颜色混合是 C++ 级别的运算,不需要 JS 引擎的参与。
| 方案 | 1000 次混合耗时 | 首屏依赖 |
|---|---|---|
color-mix() (CSS) |
~0.3ms | 0 KB |
chroma-js (JS) |
~15ms | 42 KB |
tinycolor2 (JS) |
~8ms | 14 KB |
Sass mix() (构建时) |
0ms (运行时) | 需要构建 |
💡 五、最佳实践与避坑指南
✅ 推荐做法:
- ✅ 在设计系统中使用 OKLCH 定义基础色,用
color-mix()派生色板 - ✅ 渐变统一使用
in oklab色彩空间,避免灰色中间态 - ✅ 用 CSS 变量存储基础色值,让
color-mix()自动跟随主题切换 - ✅ 使用
@supports做渐进增强,确保旧浏览器有可用的回退色值 - ✅ 在
linear-gradient中用in oklch获得更自然的彩虹渐变
❌ 避免做法:
- ❌ 不要在
color-mix()中混用不同颜色空间的输入(如color-mix(in oklch, rgb(...), hsl(...))) - ❌ 不要用
color-mix()替代opacity——半透明效果用/ <alpha>语法更语义化 - ❌ 不要假设所有设备都能显示 P3 色域——始终提供 sRGB 回退
- ❌ 不要在动画中高频触发
color-mix()——虽然性能好,但合并到@property动画中更高效
🏁 总结
CSS 现代颜色系统——color-mix()、oklch()、oklab() 和相对颜色语法——标志着前端颜色处理从「构建时静态计算」到「运行时原生计算」的范式转变。你不再需要引入 42KB 的 chroma-js 来混合颜色,不需要 Sass 的 lighten() / darken() 来调整色阶,不需要手动维护 50 个设计系统色值。
对于现有项目的迁移策略,我的建议是:
- 新项目直接用 OKLCH——所有颜色定义统一使用
oklch()函数 - 存量项目渐进迁移——在
@supports中引入color-mix()替代 Sass 颜色函数 - 设计系统优先迁移——将色板生成逻辑从 JS/Sass 迁移到
color-mix()+ CSS 变量
⚡ 关键结论: 2026 年的 CSS 已经拥有完整的颜色计算能力。
color-mix()+ OKLCH + 相对颜色语法的组合,可以覆盖 Sass 颜色函数 100% 的使用场景,而且零依赖、支持运行时动态计算、性能更好。如果你的项目已经使用了现代构建工具和最新浏览器,是时候把颜色计算逻辑从 JS/Sass 迁移到 CSS 原生方案了。
🔧 相关工具推荐
- MDN color-mix() 文档 — 官方规范与完整示例
- OKLCH Color Picker — 可视化 OKLCH 颜色空间
- CSS Color Module Level 4 规范 — W3C 颜色模块完整规范
- jsjson.com CSS 工具箱 — 在线 CSS 格式化与压缩工具
- State of CSS 2025 调查 — CSS 特性采用率追踪