意见征求:色彩空间

2022年9月21日发布,作者:Miriam Suzanne 和 Natalie Weizenbaum

最近,CSS 色彩规范方面取得了很多令人兴奋的进展,并且随着它开始在浏览器中落地,我们也一直在准备在 Sass 中添加对它的支持。其中第一部分也是最大的一部分是为 Sass 添加对色彩空间的支持,这代表着对颜色工作方式的巨大(但很大程度上向后兼容)的重新思考。

从历史上看,CSS 中的所有颜色都存在于同一个色彩空间中,称为“sRGB”。无论您是将其表示为十六进制代码、hsl() 函数还是颜色名称,它们都表示您可以告诉屏幕显示的同一组可见颜色。虽然从概念上讲这很简单,但它也存在一些主要的缺点。

  • 随着时间的推移,显示器得到了改进,它们能够显示比 sRGB 色彩空间中所能表示的颜色更多的颜色。

  • 即使您通过 hsl() 使用 sRGB,它与人类感知颜色的方式也不太对应。青色看起来明显比具有相同饱和度和亮度值的紫色更亮。

  • 无法表示特定于域或设备的色彩空间,例如打印机使用的CMYK 色彩空间。

色彩空间解决了所有这些问题。现在,并非每种颜色都有红色、绿色和蓝色通道(可以解释为色相、饱和度和亮度)。相反,每种颜色都有一个特定的色彩空间,该空间指定它具有的通道。例如,颜色 oklch(80% 50% 90deg) 的色彩空间为 oklch,亮度为 80%,色度为 50%,色相为 90deg

Sass 中的色彩空间Sass 中的色彩空间永久链接

今天,我们宣布了关于如何在 Sass 中处理色彩空间的提案。除了扩展 Sass 的颜色值以支持色彩空间之外,此提案还定义了 CSS 颜色级别 4 中所有颜色函数的 Sass 化版本。

经验法则经验法则永久链接

在 Sass 中使用色彩空间有一些经验法则。

  • rgbhslhwb 空间被认为是“传统空间”,为了向后兼容,它们通常会得到特殊处理。使用十六进制表示法或 CSS 颜色名称定义的颜色被认为是 rgb 色彩空间的一部分。传统颜色以最兼容的格式输出。这与 CSS 自己的向后兼容行为相匹配。

  • 否则,在给定空间中定义的任何颜色都将保留在该空间中,并以该空间输出。

  • 作者可以通过使用 color.to-space() 显式转换颜色的空间。这对于通过转换为非传统空间来强制执行非传统行为,或者通过在输出之前将颜色转换为传统空间来确保颜色输出与旧版浏览器兼容,非常有用。

  • srgb 色彩空间等效于 rgb,只是一个是传统空间,另一个不是。它们还使用不同的坐标系,rgb() 接受 0-255 的范围,而 srgb 使用 0-1 的范围。

  • 允许指定色彩空间进行操作的颜色函数始终默认使用源色彩空间。当为操作提供显式空间时,结果颜色仍将以与原始颜色相同的空间返回。对于 color.mix(),第一个颜色参数被认为是原始颜色。

  • 所有传统和 RGB 样式空间都表示有界颜色的色域。由于将颜色映射到色域是一个有损过程,因此通常应将其留给浏览器,浏览器可以根据显示器的功能按需映射颜色。因此,只要有可能,Sass 就会维护超出色域的通道值,即使在转换为有界色域的色彩空间时也是如此。唯一的例外是 hslhwb 色彩空间无法表达超出色域的颜色,因此将颜色转换为这些空间也将进行色域映射。作者还可以使用 color.to-gamut() 函数执行显式色域映射。

  • 旧版浏览器需要 srgb 色域中的颜色。但是,大多数现代显示器都支持更宽的 display-p3 色域。

标准 CSS 颜色函数标准 CSS 颜色函数永久链接

oklab()oklch()oklab() 和 oklch()永久链接

oklab()(立方)和 oklch()(柱面)函数提供对感知均匀空间中无限色域颜色的访问。作者可以使用这些函数来定义可靠的均匀颜色。例如,以下颜色在亮度和饱和度方面在感知上相似。

$pink: oklch(64% 0.196 353); // hsl(329.8 70.29% 58.75%)
$blue: oklch(64% 0.196 253); // hsl(207.4 99.22% 50.69%)

oklch() 格式使用一致的“亮度”和“色度”值,而 hsl() 格式显示“亮度”和“饱和度”的剧烈变化。因此,oklch 通常是进行一致转换的最佳空间。

lab()lch()lab() 和 lch()永久链接

lab()lch() 函数提供对无限色域颜色的访问,该空间的感知均匀性不如 OKLab 和 OKLCH,但采用率更高。

hwb()hwb() 永久链接

Sass 现在支持一个顶级 hwb() 函数,该函数使用与 CSS 内置 hwb() 语法相同的语法。

color()color() 永久链接

新的 color() 函数提供了对许多专业空间的访问。最值得注意的是,display-p3 是宽色域显示器的常用空间,这使其成为希望简单地访问更广泛颜色范围的作者最受欢迎的选择之一。例如,P3 绿色比 sRGB 中可用的绿色明显“更亮”且更饱和。

$fallback-green: rgb(0% 100% 0%);
$brighter-green: color(display-p3 0 1 0);

Sass 将原生支持颜色级别 4 规范中声明的所有预定义色彩空间。它还将支持未知色彩空间,尽管这些空间无法转换为任何其他色彩空间,反之亦然。

新的 Sass 颜色函数新的 Sass 颜色函数永久链接

color.channel()color.channel() 永久链接

此函数返回颜色中单个通道的值。默认情况下,它仅支持颜色自身空间中可用的通道,但您可以传递 $space 参数以在转换为给定空间后返回通道的值。

$brand: hsl(0 100% 25.1%);

// result: 25.1%
$hsl-lightness: color.channel($brand, "lightness");

// result: 37.67%
$oklch-lightness: color.channel($brand, "lightness", $space: oklch);

color.space()color.space() 永久链接

此函数返回颜色的空间名称。

// result: hsl
$hsl-space: color.space(hsl(0 100% 25.1%));

// result: oklch
$oklch-space: color.space(oklch(37.7% 38.75% 29.23deg));

color.is-in-gamut()color.is-legacy()color.is-in-gamut()、color.is-legacy() 永久链接

这些函数返回有关颜色的各种信息。color.is-in-gamut() 返回颜色是否在其色彩空间内(而不是其一个或多个通道超出范围,例如 rgb(300 0 0))。color.is-legacy() 返回颜色是否为 rgbhslhwb 色彩空间中的传统颜色。

color.is-powerless()color.is-powerless() 永久链接

此函数返回给定颜色中给定通道是否“无能”。这是一种为各个色彩空间定义的特殊状态,表示通道的值不会影响颜色的显示方式。

$grey: hsl(0 0% 60%);

// result: true, because saturation is 0
$hue-powerless: color.is-powerless($grey, "hue");

// result: false
$hue-powerless: color.is-powerless($grey, "lightness");

color.same()color.same() 永久链接

此函数返回两种颜色是否将以相同的方式显示,即使这需要在空间之间转换。这与 == 运算符不同,后者始终认为不同非传统空间中的颜色是不相等的。

$orange-rgb: #ff5f00;
$orange-oklch: oklch(68.72% 20.966858279% 41.4189852913deg);

// result: false
$equal: $orange-rgb == $orange-oklch;

// result: true
$same: color.same($orange-rgb, $orange-oklch);

现有的 Sass 颜色函数现有的 Sass 颜色函数永久链接

color.scale()color.adjust()color.change()color.scale()、color.adjust() 和 color.change()永久链接

默认情况下,所有 Sass 颜色转换都在原始颜色参数的色彩空间中处理和返回。但是,所有相关函数现在都允许为转换指定显式色彩空间。例如,亮度和暗度调整在 oklch 中最可靠。

$brand: hsl(0 100% 25.1%);

// result: hsl(0 100% 43.8%)
$hsl-lightness: color.scale($brand, $lightness: 25%);

// result: hsl(5.76 56% 45.4%)
$oklch-lightness: color.scale($brand, $lightness: 25%, $space: oklch);

请注意,即使在不同空间中执行调整,返回的颜色仍以原始色彩空间输出。

color.mix()color.mix() 永久链接

color.mix() 函数将保留其对传统色彩空间的现有行为,但对于新的色彩空间,它将匹配 CSS 的“颜色插值”规范。这是 CSS 计算渐变或动画中两个颜色之间使用哪种颜色的方式。

弃用弃用永久链接

许多现有函数仅对传统颜色有意义,因此正在弃用,取而代之的是像 color.channel()color.adjust() 这样的色彩空间友好函数。

  • color.red()
  • color.green()
  • color.blue()
  • color.hue()
  • color.saturation()
  • color.lightness()
  • color.whiteness()
  • color.blackness()
  • adjust-hue()
  • saturate()
  • desaturate()
  • transparentize()/fade-out()
  • opacify()/fade-in()
  • lighten()/darken()

请告诉我们您的想法!请告诉我们您的想法!永久链接

此提案还有更多细节,并且尚未最终确定。我们希望获得您对此的反馈!请在GitHub 上阅读,并提交问题,提出您可能有的任何想法或疑虑。