Back

CSS 相对颜色语法详解

CSS 相对颜色语法详解

如果你曾经为了创建品牌色的半透明版本而定义了十几个自定义属性,那么你已经理解了 CSS 相对颜色语法所解决的问题。这个特性让你可以在任何现代 CSS 颜色函数中直接从现有颜色派生新颜色——无需预处理器、无需 JavaScript、无需额外的变量。

核心要点

  • CSS 相对颜色语法使用 from 关键字从现有的原始颜色派生新颜色,通过将其各个通道暴露为可修改的变量来实现。
  • 它适用于 rgb()hsl()hwb()lab()lch()oklab()oklch()
  • OKLCH 是进行颜色操作的首选色彩空间,因为其亮度通道具有感知均匀性,能在不同色相中产生视觉上一致的结果。
  • 相对颜色可以自然地集成到基于 token 的设计系统中,让你只需定义一个基础颜色,就能从中派生出所有变体,无需预处理器或构建步骤。

什么是 CSS 相对颜色语法?

CSS 相对颜色在 CSS Color Level 5 规范中定义,它允许你获取一个现有颜色——称为原始颜色——并将其各个通道作为变量来构造新颜色。关键的新增元素是 from 关键字。

基本结构如下:

color-function(from <origin-color> channel1 channel2 channel3)

当浏览器遇到 from 时,它会将原始颜色转换为目标色彩空间,将每个通道暴露为命名变量,并允许你将这些变量——无论是修改过的还是未修改的——作为输出值传递。

这适用于现代 CSS 颜色函数,如 rgb()hsl()hwb()lab()lch()oklab()oklch()

CSS from 颜色语法的工作原理

看这个简单的例子:

/* 原始颜色: green */
/* 暴露的通道: r=0, g=128, b=0 */
color: rgb(from green r g b); /* 输出 rgb(0 128 0) */

这里的输出与输入相同,但真正的强大之处在于你可以使用 calc() 修改各个通道:

/* 将色相旋转 180 度以获得互补色 */
background: hsl(from blue calc(h + 180) s l);

/* 通过乘以亮度通道来提亮 */
background: oklch(from blue calc(l * 1.25) c h);

/* 降低不透明度而无需单独的变量 */
background: rgb(from lime r g b / 50%);

通道值在函数内部解析为纯数字,因此 calc() 算术运算可以顺畅进行,不会出现单位不匹配的问题。

为什么 OKLCH 相对颜色值得使用

并非所有色彩空间在操作时都是平等的。HSL 很常见,但其亮度通道不具有感知均匀性——在不同色相上以相同量调整 l 会产生视觉上不一致的结果。

OKLCH 解决了这个问题。它的亮度通道具有感知均匀性,这意味着无论色相如何,+0.1 的变化看起来都像是相同的视觉步长。这使它成为生成色调、阴影和可访问对比度配对的有力选择。

如果你不熟悉感知色彩空间,Björn Ottosson 介绍的 OKLab/OKLCH 色彩模型解释了这些新色彩空间背后的原理。

/* 变暗 25% */
background: oklch(from var(--color-primary) calc(l * 0.75) c h);

/* 生成高对比度的文本颜色 */
color: oklch(from var(--color-primary) calc(l + 0.6) c h);

注意 OKLCH 中的亮度通道范围是从 01,因此 calc(l + 0.6) 的变化是相当大的。超出有效范围的值会被浏览器自动限制。

相对颜色 vs. color-mix()

这两个 CSS 颜色特性服务于不同的目的。color-mix() 以指定比例混合两种颜色。CSS 相对颜色直接操作单个原始颜色的通道。如果你需要悬停状态、柔和变体或不透明度调整的 token,相对语法是正确的工具。如果你需要在两种不同颜色之间插值,请使用 color-mix()

融入基于 Token 的设计系统

这是 CSS 相对颜色真正发光的地方。定义一个基础 token,然后从中派生所有变体:

:root {
  --color-primary: #3b82f6;

  --color-primary-hover:    oklch(from var(--color-primary) calc(l * 0.9) c h);
  --color-primary-active:   oklch(from var(--color-primary) calc(l * 0.8) c h);
  --color-primary-disabled: oklch(from var(--color-primary) l c h / 0.5);
  --color-on-primary:       oklch(from var(--color-primary) calc(l + 0.6) c h);
}

更改 --color-primary,所有派生的 token 都会自动更新。无需 Sass 函数,无需构建步骤。

浏览器支持

相对颜色语法在 Chromium、Firefox 和 Safari 的现代版本中受支持。使用 @supports 安全地进行功能检测:

@supports (color: rgb(from white r g b)) {
  /* 相对颜色语法可用 */
}

对于不支持的浏览器,在相对颜色声明之前提供一个回退颜色。层叠机制确保旧浏览器使用静态值,而现代浏览器会覆盖它:

.button {
  background: #3b82f6;
  background: oklch(from var(--color-primary) calc(l * 0.9) c h);
}

总结

CSS 相对颜色语法用一个单一、可读的模式替代了整个类别的预处理器逻辑。选择 OKLCH 以获得感知一致的亮度调整,当需要直接控制饱和度时使用 hsl(),并将所有内容连接到自定义属性,这样你的整个调色板就能从一个源 token 保持同步。

常见问题

可以。你可以使用 var() 将任何自定义属性作为原始颜色传递。例如,oklch(from var(--brand-color) calc(l * 0.8) c h) 可以按预期工作。浏览器首先解析变量,然后将结果颜色转换为目标色彩空间并暴露其通道。

浏览器会自动限制超出范围的值。例如,如果 calc() 表达式将 OKLCH 亮度推到 1 以上或 0 以下,浏览器会将其裁剪到有效范围。这意味着在大多数情况下你不需要手动防止溢出。

对于典型使用,性能影响可以忽略不计。浏览器在计算值时解析相对颜色,类似于在其他属性中解析 calc()。只有在单个页面上有数千个相对颜色声明时,才会出现任何可测量的差异。

如果一个转换的结果解析为有效的颜色值,则可以链接相对颜色函数。在实践中,开发者通常将相对颜色计算的结果分配给自定义属性,并将其用作另一个转换的原始颜色,从而允许多步骤的颜色操作,同时保持代码的可读性。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay