配了三年主题色,每次加个 hover 态都要把 RGB 三个通道重写一遍——今天这件事被 CSS 相对颜色语法彻底原生化了

配了三年主题色,每次加个 hover 态都要把 RGB 三个通道重写一遍——今天这件事被 CSS 相对颜色语法彻底原生化了


设计师给了你一个主色,叫 --brand: oklch(60% 0.18 240)。你问:「那 hover 态呢?」她说:「浅一点。」你打开 Figma,记下 RGB 值,转换成 HSL,调低明度,再写回 CSS。

这个过程,从一个颜色生出另一个颜色,在 2026 年之前没有原生方案。CSS Color Level 5 的相对颜色语法(Relative Color Syntax)把这个洞彻底填上了。

核心就一个关键字:from

/* 旧的解法:把一个颜色拆成三个变量,手动组装 */
:root {
  --brand-h: 240deg;
  --brand-s: 60%;
  --brand-l: 50%;
  --brand: hsl(var(--brand-h) var(--brand-s) var(--brand-l));
  --brand-hover: hsl(var(--brand-h) var(--brand-s) calc(var(--brand-l) - 10%));
}
/* 新的解法:一行,从 var(--brand) 直接派生 */
:root {
  --brand: oklch(60% 0.18 240);
  --brand-hover: oklch(from var(--brand) l calc(c * 1.2) h);
}

from 关键字后面跟一个颜色,浏览器会把这个颜色拆解成该色彩空间的各个通道变量,你可以在新的颜色里复用、运算。oklch(from var(--brand) l c h) 里的小写 lch 就是浏览器提供的变量。

三个通道,怎么调

OKLCH 之所以比 HSL 更适合做颜色运算,是因为它的三个通道是「人眼友好」的:

  • L(Lightness):感知亮度,0% 是黑,100% 是白
  • C(Chroma):色度,可以理解为饱和度
  • H(Hue):色相,0-360 度

calc() 调它们是最直观的:

/* 浅色版:亮度加 30%,色度不变,色相不变 */
--brand-light: oklch(from var(--brand) calc(l + 0.30) c h);

/* 深色版:亮度减 35% */
--brand-dark: oklch(from var(--brand) calc(l - 0.35) c h);

/* 降饱和:色度砍半 */
--brand-muted: oklch(from var(--brand) l calc(c * 0.5) h);

/* 换个色相:顺时针转 30° */
--brand-shifted: oklch(from var(--brand) l c calc(h + 30));

注意这些 lch 变量是浏览器解析后提供的,和大小写精确对应,写错就变成了绝对值。

实用场景:一个 token 生成整套色板

相对颜色语法最杀手级的用法是从一个 base 色,自动生成一套完整的 UI 调色板:

:root {
  --brand: oklch(55% 0.18 265);
}

[data-theme="light"] {
  --bg: oklch(from var(--brand) 98% 0.015 h);
  --surface: oklch(from var(--brand) 96% 0.02 h);
  --text: oklch(from var(--brand) 15% 0.05 h);
  --button: oklch(from var(--brand) 48% 0.22 h);
  --border: oklch(from var(--brand) 85% 0.03 h);
}

[data-theme="dark"] {
  --bg: oklch(from var(--brand) 12% 0.015 h);
  --surface: oklch(from var(--brand) 18% 0.02 h);
  --text: oklch(from var(--brand) 92% 0.02 h);
  --button: oklch(from var(--brand) 65% 0.25 h);
  --border: oklch(from var(--brand) 30% 0.03 h);
}

只要改一个 --brand 的值,深浅两套主题色全部自动更新。用 oklch(from ...) 生成的单色色板,饱和度随亮度变化的曲线是感知均匀的——不会出现在 HSL 里「同样减 20% 明度,蓝色比红色暗得多」的失真问题。

不仅是 OKLCH,color(from ...) 还支持所有色彩空间(srgb、display-p3、hsl 等),进什么颜色空间,变量就对应那个空间的通道。

浏览器支持

Chrome 119+、Safari 16.4+、Firefox 128+,全球覆盖率 87% 以上,2026 年可以直接用。Safari 是最后一家跟进的大浏览器,16.4 就支持了。渐进增强写法:如果想保底,fallback 就是不生效——颜色用原始值,不会报错。

下一步

  1. 找到项目里的颜色变量——通常在 tokens.css 或 design token 文件里
  2. 选一个 base 色,测试 oklch(from var(--base) calc(l ± 0.xx) c h) 派生变体
  3. 把旧的手动 HSL 拆解替换成相对颜色语法,减少 CSS 变量数量
  4. color-gamut 检测高色域支持,给 P3 屏幕单独覆盖 display-p3 调色板

一个 from,把「颜色」这个离散的静态值,变成了可以参与运算的动态系统。

评论区

0 条评论

登录后可评论。