意見徵集 (RFC):色彩空間

由 Miriam Suzanne 和 Natalie Weizenbaum 於 2022 年 9 月 21 日發佈

最近 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 版本。CSS 色彩等級 4

經驗法則經驗法則永久連結

在 Sass 中使用色彩空間有幾個經驗法則。

  • `rgb`、`hsl` 和 `hwb` 空間被認為是「傳統空間」,為了向下相容,通常會對其進行特殊處理。使用十六進位表示法或 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 將原生支援 Colors Level 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 上閱讀它,並提出 issue,分享您的任何想法或疑慮。