色彩科學
Published:Updated:
修復 Blowfish 文字對比度過低的問題,隨筆記錄這次修復學到的東西。
起因
Blowfish 使用 neutral / primary / secondary 的色彩框架,這和 Material Design 的架構類似,扣掉 Material Design 沒有 neutral,primary 是主要品牌顏色、主要的突出顏色,secondary 是次要但需要強調的地方,應該少量謹慎使用。
問題來了,Blowfish 雖然用了類似 Material Design 的架構,但是很多顏色都不照 Material Design 設計,比如內建主題很多 neutral 都不是灰色系,再加上大量使用 blur 和透明效果就導致對比度過低,研究該怎麼系統性的修復的過程中把知識整理成這篇文章,雖然評估後沒用到,但還是把知識寫起來。
色彩模型和色彩空間
別看筆者這樣,筆者當年好歹也是修過顯示器導論的,但是網路繁體中文資源笑死人,連頂著色研所名稱的公司寫的文章都錯,隨便找還找到台師大碩士論文,CTRL+F LCH 一秒就找到論文錯誤,說 LCH 是色彩空間,繁體中文資源真的是有夠爛。
色彩模型是用來描述色彩的座標軸,從小學的 RGB 到 HSL 和 LCH 都是不同的色彩模型,不同的座標軸有各自的特性和表現能力,比如 HEX 就沒辦法描述 DCI-P3 色彩空間。
色彩空間則是表達有多豐富的顏色,主要用在硬體規格上,比如說我這台螢幕可以顯示 DCI-P3 色彩空間,那麼電影拍 DCI-P3 這台螢幕就能顯示那些顏色。常見的色彩空間由低階到高階大概有 45% NTSC / 72% NTSC (100% SRGB) / DCI-P3 / Rec.2020 / Adobe RGB,前兩個是一般螢幕,接下來兩個是影視作品,最後一個用於紙本影印。
產品的色彩空間也不是越大越好,比如說 Windows 色彩管理一團亂,色彩空間大反而顏色容易過飽和,尤其是低階硬體的廣色域根本沒在管色彩映射,色準、校色也理所當然直接關係此問題。
然後碩士論文、開公司的開頭就說 LCH 是色彩空間,你只有真的在算數學搞線代凸優化那些的人才會把座標軸稱作空間...所以這些人講空間肯定是自己都搞不懂才會誤用名詞。
色彩模型
本文還是只會介紹 CSS 用到的那幾個模型,包含 RGB/HEX/HSL/OKLCH。
RGB and Hex
最古老的色彩模型,用紅綠藍三原色組成,最大的問題是
- 開發者難以從數值判斷色相、對比度、亮度
- 對比度和亮度無法直接手調
HEX 和 RGB 是一樣東西只是改成 16 進位,為了解決此問題於是有了 HSL 模型。
HSL
HSL(Hue 色相,Saturation 飽和度,Lightness明度)解決了上面的問題,可以看到座標完全不同並且直接給你獨立座標專門調整亮度。
這基本上就是 Adobe Lightroom 裡面調整顏色的方式,然而 HSL 只解決了一半問題,另一半的問題是不同色相的亮度數值即使一樣,人眼感受到還是不一樣亮。
可以看到亮度設定相同但是黃色明顯更亮,黑色文字在藍色背景下就顯得對比度不足。此外 HSL 和 RGB 都使用 RGB 色彩空間,因此在支援更高色彩空間的顯示器就無法顯示更豐富的顏色。
OKLCH
LCH 分別代表 Lightness 亮度、Chroma 彩度、Hue 色相,OK 代表沒問題版本的 LCH,至於是改了什麼也不用在意了,反正你不會用 LCH,此標準 2020 才推出,2023 就光速被所有瀏覽器實作支援,這毫無疑問是非常誇張的速度。
HSL 到 OKLCH 之間其實還有 LAB/OKLAB/LCH 最後才是 OKLCH,最重要的改變是解決 HSL 的亮度問題,並且支援 DCI-P3 色彩空間。
這樣用文字介紹讀者可能無感,但是實際看設定就知道,RGB 格式對開發者來說就是魔法數字(亂碼):
:root {
--color-primary-50: rgb(239, 246, 255);
--color-primary-100: rgb(219, 234, 254);
--color-primary-200: rgb(191, 219, 254);
--color-primary-300: rgb(147, 197, 253);
--color-primary-400: rgb(96, 165, 250);
--color-primary-500: rgb(59, 130, 246);
--color-primary-600: rgb(37, 99, 235);
--color-primary-700: rgb(29, 78, 216);
--color-primary-800: rgb(30, 64, 175);
--color-primary-900: rgb(30, 58, 138);
}
轉成 OKLCH 之後就能很明顯的看出都是類似色相並且亮度級減:
:root {
--color-primary-50: oklch(97.048% 0.01429 254.737);
--color-primary-100: oklch(93.192% 0.0317 255.644);
--color-primary-200: oklch(88.235% 0.05716 254.166);
--color-primary-300: oklch(80.908% 0.09569 251.839);
--color-primary-400: oklch(71.375% 0.14347 254.643);
--color-primary-500: oklch(62.31% 0.1881 259.83);
--color-primary-600: oklch(54.616% 0.21529 262.896);
--color-primary-700: oklch(48.821% 0.21724 264.392);
--color-primary-800: oklch(42.446% 0.18094 265.652);
--color-primary-900: oklch(37.907% 0.13782 265.536);
}
一目了然而且沒有色相之間的亮度問題,非常好模型。
至於是否該採用 OKLCH?他在 2023 之後的瀏覽器才能用,但是如果你的專案和 Blowfish 一樣使用 Tailwind V4 又沒額外設定,那麼 Tailwind V4 預設會使用 2024 之後的瀏覽器才支援的原生 CSS nesting 語法,這也代表用戶都有新瀏覽器,沒必要用 @support 檢查。
不過還有別的問題,在不支援 DCI-P3 的硬體中 OKLCH 會回退成 RGB 色彩空間,造成顏色無法在用戶裝置正確顯示。而且不支援 DCI-P3 的硬體非常多,雖然手機基本上全都支援了,但是低階筆電不用想連 72% NTSC 都沒有,一般筆電也才勉強 100% SRGB,中高階才會看到支援 DCI-P3,電腦螢幕也是如此。
唯一的解決方案是用 https://oklch.com/ 這種工具檢查顏色有沒有超出範圍,是目前硬體支援度不夠的妥協。
學到了什麼
整理一下這次修復對比度學了哪些東西。
- 不要自創規範,Blowfish 用了 10 級色彩,然而 Tailwind 用了 11 級因此無法直接套用市面上的 Tailwind 色彩產生器。
- Blowfish 用了類似 Material Design 的架構但是完全沒有用他的邏輯,造成更多問題。
- 這些問題會變成歷史包袱越來越重,如果沒歷史包袱就直接改了沒這麼多麻煩。
- 源頭是 fork congo 主題時把問題一路繼承過來了
- 灰色是整個網站用最多的顏色,忘記在哪裡看到這句話的,可以看到 Tailwind 確實內建一堆灰色。
- Refactoring UI 有教學文章說明如何自建色彩主題。
- tints.dev 根據 Refactoring UI 建立了 Tailwind 色彩生成器。
- Material Design Palette Generator 可以快速建立 Material Design 的顏色。
- Tailwind 內建顏色 不固定 OKLCH 的 H,數值會浮動。
- oklch-smooth 用 OKLCH 建立視覺鮮明的資料可視化顏色。
- colorbrewer2 用於地圖數據的顏色。
- Unix 合併輸出可以用 subshell
(echo 'html:not(.dark) {'; hugo gen chromastyles --style=emacs; echo '}') >> assets/css/custom.css - PowerShell 合併輸出可以用 array sub-expression operator
@("html:not(.dark) {"; (hugo gen chromastyles --style=emacs); "}") | Add-Content -Path "assets/css/custom.css"