设计师给你的 P3 色值写进 CSS,新手机艳、旧手机灰——这件事今天被 color() 彻底原生化了
设计师给你的色值写进 CSS,新一代 MacBook 上鲜艳夺目,旧手机打开直接偏了另一个颜色——这件事,今天被 CSS 彻底原生化了。
根子在哪儿
CSS 传统上只认 sRGB。你拿到一个 P3 色域的亮红色 #E63946,在 iPhone 15 Pro 上打开,Safari 会把它压缩回 sRGB,色相没问题,但饱和度砍掉一大截,看起来灰扑扑的。以前要靠 JS 颜色库(比如 chroma.js)或者设计工具导出多套色板来解决。
color() 把这件事放进了 CSS 语法里
Chrome 111 / Safari 15.4 / Firefox 113 全部支持,2026 年已经是稳稳的 Baseline。
写法和以前完全不一样:
/* 传统写法,强制 sRGB */
color: #E63946;
/* 在 display-p3 色彩空间里定义这个颜色 */
color: color(display-p3 0.90 0.22 0.27);
这个亮红色在 sRGB 范围外还有余量,写成 #E63946 等于把它的 P3 极限压缩了。color(display-p3 ...) 直接在正确的色彩空间里表达它,Safari 和 Chrome DevTools 会在支持 P3 的屏幕上显示「Display P3」标签。
三行代码,同时覆盖两种屏幕
.btn-primary {
background: #E63946; /* sRGB 兜底 */
background: color(display-p3 0.90 0.22 0.27); /* P3 增强 */
}
浏览器认识 color() 的会渲染 P3;旧设备不认识就跳过,用上面的 hex。两个颜色视觉上几乎一样,但 P3 屏幕看起来更「活」。
相对颜色语法:一条 token 生成整套色板
这才是真正的杀手级用法。传统做法是设计师给你一套 10 个色阶,每个都要单独写进 CSS。相对颜色语法让你只定义一个变量,其他全部从它推导:
:root {
--brand: oklch(55% 0.21 25); /* 基础品牌红,只要一个 */
}
/* 生成更亮的变体,只改 L 通道 */
.btn-primary {
background: oklch(from var(--brand) calc(l * 1.3) c h);
}
/* 生成暗色变体 */
.btn-primary:active {
background: oklch(from var(--brand) calc(l * 0.7) c h);
}
/* 生成透明度版本 */
.btn-primary:disabled {
background: oklch(from var(--brand) l c h / 0.4);
}
from 关键字把 --brand 的三个通道(L、C、H)拆出来给你用,然后用 calc() 做运算。以前这个要靠 Sass 的 darken() 函数或者 JS 跑半天,现在纯 CSS,浏览器自己算。
OKLCH vs OKLAB:选哪个通道来改
OKLCH 是极坐标形式(L = 明度,C = 饱和度,H = 色相),OKLAB 是直角坐标。实操经验:
- 只改明度 → 用 OKLCH,
calc(l * 0.8)直接把颜色调暗,饱和度和色相不变,结果和人眼感受一致 - 要做渐变或者色彩混合 → 用 OKLAB,它的通道更符合人眼感知,混合出来更自然
/* OKLCH 做明度渐变,人眼看起来均匀 */
background: linear-gradient(
to right,
oklch(95% 0.05 250),
oklch(55% 0.21 250),
oklch(25% 0.15 250)
);
用 HSL 做这个渐变,中间段会突然变灰,因为 HSL 的「饱和度」通道和人眼感知不线性。
color() 配合 @media (color-gamut) 做渐进增强
如果你需要更精确的控制,可以用媒体查询只对 P3 屏幕注入增强色:
.card {
background: #f8f9fa; /* 基础 */
}
@media (color-gamut: p3) {
.card {
background: color(display-p3 0.98 0.98 0.97);
}
}
这个查询只有浏览器和屏幕同时支持 P3 时才会触发,比 @supports 更精准——因为它测的是硬件能力,不是浏览器版本。
和旧方案对比
| 方案 | P3 支持 | 推导变体 | 打包体积 | 运行时 |
|---|---|---|---|---|
| 纯 hex / HSL | ❌ | ❌ | 0 | ❌ |
| JS 颜色库(chroma.js) | ✅ | ✅ | ~35KB | ✅ |
| Sass 函数 | ❌ | ✅ | 0 | ❌(编译时) |
CSS color() + OKLCH |
✅ | ✅ | 0 | ❌ |
Sass 函数在编译时跑,生成的 CSS 又是静态值,切换主题色还是要重编译。CSS 相对颜色语法在浏览器里实时算,配合 CSS 自定义属性,真正做到了零体积、零 JS、主题色动态切换。
下一步
如果你的项目还在用 hex 写所有颜色,建议从现在开始只用一个 OKLCH 基础 token,然后用 color() 和相对语法生成其他变体。Chrome DevTools 现在会在颜色 picker 里标注当前颜色所在的色域,拿一个支持 P3 的 Mac 打开你的页面,看颜色边上有没有「Display P3」字样——有就说明已经用对了地方。
这件事把设计师到前端的颜色传递链路彻底变了:设计师给一个 OKLCH 值,前端直接写进去,其他色阶全部由浏览器实时推导,不用再手动维护一套色板,也不用担心新手机打开偏色。
评论区
登录后可评论。