🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

現代 CSS 顏色使用指南

1. 前言

大多數開發者處理顏色時,就是從設計稿裡複製粘貼一個色值,然後就完事了。

但是!CSS 顏色在過去幾年裡發生了很多變化!

不僅從 Web 十六進制代碼演變成了 hsl() 函數,而且就連你熟知的 rgb() 函數也跟以前不同了!

不信我們接著往下看。

2. 現代 CSS 寫法

2.1. 你不需要添加 a

以前,我們用 rgb() 填寫普通的 RGB 顏色值,要想改變不透明度,就必須使用 rgba()

.red {
  color: rgb(255, 0, 0);
}

.red-50 {
  color: rgba(255, 0, 0, 0.5);
}

現在,你可以直接添加第 4 個通道了:

.red {
  color: rgb(255, 0, 0);
}

.red-50 {
  color: rgb(255, 0, 0, 0.5);
}

而且,不用擔心瀏覽器兼容問題,只要你不用支持 IE。

2.2. 空格分隔語法

除此之外,逗號現在也被視為舊語法了,對於新的顏色函數,我們甚至不能再使用逗號,只能使用新的空格語法。

.red {
  color: rgb(255 0 0);
}

.blue {
  color: hsl(226 100% 50%);
}

不過,使用空格分隔語法時要注意:你不能為 alpha 通道添加第四個值。

換句話說,這樣寫 color: rgb(255 0 0 0.5) 是不可以的。

如果你要添加第 4 個值,你需要在字母值之前使用一個正斜杠:

.red {
  color: rgb(255 0 0);
}

/* 50% 透明 */
.red-50 {
  color: rgb(255 0 0 / 0.5);
}

.hsl-red-50 {
  color: hsl(0 100% 50% / 0.5);
}

為什麼要這麼做呢?

因為 CSS 新增了很多顏色函數,統一用斜杠可以快速區分“顏色值”和“透明度”,看代碼時一目了然。

2.3. hsl() 也變了

單位現在可選了:

.red {
  color: hsl(0deg 100% 50%);
}

.also-red {
  color: hsl(0deg 100 50);
}

.another-red {
  color: hsl(0 100% 50%);
}

.this-is-red-too {
  color: hsl(0 100 50);
}

小提示:最好還是保留百分號,因為 VS Code 只有帶百分號的才會顯示顏色預覽。

3. 相對顏色

相對顏色是什麼?

簡單說就是基於現有顏色生成新顏色。

3.1. 基礎用法

我們從一個簡單的例子開始:

.rgb-red {
  color: rgb(from #ff0000 r g b);
}

這行代碼的意思是:

基於 #ff0000 這個顏色,提取它的紅(r)、綠(g)、藍(b)值,然後用這些值創建一個新顏色。

結果其實就是 rgb(255 0 0)

看起來很傻對吧?但重點是下面這個:

.rgb-red {
  color: rgb(from #ff0000 r g b);
}

/* 輕鬆創建 50% 透明度版本 */
.rgb-red-50 {
  color: rgb(from #ff0000 r g b / 0.5);
}

3.2. 最實用的場景:處理 CSS 變數

以前你想讓一個 CSS 變數顏色變透明,得這樣:

:root {
  --color-primary: #2563eb;
  --color-primary-transparent: rgba(37, 99, 235, 0.75); /* 手動轉換,麻煩! */
}

現在呢,你可以直接這樣寫:

:root {
  --color-primary: #2563eb;
}

.semi-transparent-primary-background {
  /* 直接基於變數創建透明版本 */
  background-color: hsl(from var(--color-primary) h s l / 0.75);
}

就像你有一張照片,以前想調整透明度要重新處理一遍,現在濾鏡一點就搞定。

3.3. 快速生成配色方案

我們可以快速創建基礎顏色的淺色和深色版本:

:root {
  --base: hsl(217 73% 50%);
  --base-light: hsl(from var(--base) h s 75%); /* 調亮 */
  --base-dark: hsl(from var(--base) h s 25%); /* 調暗 */
}

比如實現一個 Toast,它可能基於一種基礎顏色,然後創建一種較深的顏色用於文本,一種較淺的顏色用於背景,還需要一個不透明度較低的顏色用於陰影。

以前要 4 個值,現在直接 1 個值搞定:

.toast {
  --toast-color: #222;

  /* 深色文字 */
  color: hsl(from var(--toast-color) h s 15%);

  /* 原色邊框 */
  border: 2px solid var(--toast-color);

  /* 淺色背景 */
  background: hsl(from var(--toast-color) h s 90%);

  /* 半透明陰影 */
  box-shadow: 0 12px 12px -8px hsl(from var(--toast-color) h s l / 0.325);
}

此時換顏色也超簡單:

[data-toast="info"] {
  --toast-color: #0362fc; /* 藍色 */
}

[data-toast="error"] {
  --toast-color: hsl(0 100% 50%); /* 紅色 */
}

一個變數搞定所有顏色變體,優雅!十分優雅!

image

4. 淺暗主題切換

4.1. 以前的痛苦

不知道你是否實現過網站的淺色和深色主題:

:root {
  /* 預設淺色主題 */
  --text-heading: #000;
  --text-body: #212121;
  --surface: #efefef;

  @media (prefers-color-scheme: dark) {
    /* 暗色主題 - 第一遍 */
    --text-heading: #fff;
    --text-body: #efefef;
    --surface: #212121;
  }
}

.dark-theme {
  /* 暗色主題 - 又寫一遍! */
  --text-heading: #fff;
  --text-body: #efefef;
  --surface: #212121;
}

同樣的顏色寫兩遍,一個給媒體查詢(自動切換),一個給切換按鈕。

改一次要改兩個地方,煩死了!

4.2. 現在的解決方案:light-dark()

:root {
  /* 跟隨系統偏好 */
  color-scheme: light dark;

  /* 一次定義,自動切換 */
  --text-heading: light-dark(#000, #fff);
  --text-body: light-dark(#212121, #efefef);
  --surface: light-dark(#efefef, #212121);
}

light-dark(淺色, 暗色) 就這麼簡單!系統是淺色就用第一個,暗色就用第二個。

4.3. 添加手動切換按鈕

如果讓用戶手動切換主題:

:root {
  /* 預設跟隨系統 */
  color-scheme: light dark;
  --text-heading: light-dark(#000, #fff);
  --text-body: light-dark(#212121, #efefef);
  --surface: light-dark(#efefef, #212121);
}

/* 用戶選了淺色,鎖定 */
html[data-theme="light"] {
  color-scheme: light;
}

/* 用戶選了暗色,鎖定 */
html[data-theme="dark"] {
  color-scheme: dark;
}

4.4. 組件精細控制

如果某個區域必須保持固定顏色,比如某個背景圖上必須是白字:

.hero {
  /* 不管全局主題怎麼變,這裡永遠是淺色主題 */
  color-scheme: light;
  background: url("light-background.webp");
}

5. 漸變優化

5.1. 以前的痛苦

讓我們直接看例子,這是一個從藍到紅的漸變:

.gradient {
  --color-1: hsl(219 76 41); /* 藍色 */
  --color-2: hsl(357 68 53); /* 紅色 */
  background: linear-gradient(90deg, var(--color-1), var(--color-2));
}

中間會出現灰撲撲的顏色,不好看:

image

以前你只能手動加個中間色:

.better {
  --middle: hsl(271 52 41); /* 紫色 */
  background: linear-gradient(90deg, var(--color-1), var(--middle), /* 加一個中間色 */ var(--color-2));
}

是不是好看多了:

image

但是麻煩呀!我甚至可能需要添加兩到三個額外的色階,以確保它與原設計完全相同。

5.2. 現在的解決辦法:指定顏色空間

現在你可以輕鬆解決,只需要指定一個顏色空間:

.better {
  /* 用 oklch 顏色空間插值,中間色更鮮豔 */
  background: linear-gradient(in oklch 90deg, var(--color-1), var(--color-2));
}

就像拍照時選濾鏡,不同的顏色空間會產生不同的中間色效果。oklch 在大多數情況下效果最好。

看下效果對比:

image

唯一的真正問題是,不同的顏色空間可能更適合不同的漸變,所以有時確實需要花點時間摸索。

可選的顏色空間有:

  • oklch / lch
  • oklab / lab
  • hwb
  • xyz
  • 不指定默認是 srgb

5.3. 實現彩虹漸變

以前做彩虹要指定每一個顏色。

現在只需要:

.rainbow {
  /* 從紅色繞一整圈再回到紅色,走長路徑 */
  background: linear-gradient(in hsl longer hue 90deg, red, red);
}

longer hue 的意思是“走遠路”,這樣就能經過所有顏色了。

實現效果如下:

image

6. 超寬色域——當客戶就要那個色

有時候客戶會拿著他們的 Logo 說:“我就要這個色,一模一樣的!”

問題是,普通的 hex、rgb()hsl() 用的是 sRGB 色域,能表示的顏色有限。

這就像以前電視只能顯示幾百種顏色,然而現在的手機屏幕能顯示幾百萬種。

6.1. 解決方案:display-p3

為了滿足客戶的需求,你可以使用 color 顏色函數,並使用 display-p3 色域。

.vibrant-green {
  /* 使用 display-p3 色域,顏色更鮮豔 */
  color: color(display-p3 0 1 0);
}

如果瀏覽器不支持,會自動回退到能顯示的最接近顏色,不會出錯。

你可以在 Chrome 的開發者工具查看這種顏色:

image

點擊色塊,它會顯示你選擇的顏色,但同時也會顯示使用 sRGB 色域的顯示器的色域限制。

建議: 除非客戶真的非常在意那個特定顏色,一般用不著。但知道有這個方案總是好的。

7. 總結

現在你可以更輕鬆地寫代碼了:

  1. 少打字 - 不用區分 rgbargb,用空格代替逗號
  2. 少定義變數 - 用相對顏色基於一個顏色生成多個變體
  3. 少寫重複代碼 - light-dark() 一次定義兩套主題
  4. 更好的漸變 - 指定顏色空間讓中間色更漂亮
  5. 更精確的顏色 - 需要時可以用更寬的色域

最重要的是: 這些特性瀏覽器支持都很好了(除了 IE,但誰還在乎 IE 呢?)

我是冴羽,10 年筆耕不輟,專注前端領域,更新了 10+ 系列、300+ 篇原創技術文章,翻譯過 Svelte、Solid.js、TypeScript 文檔,著有小冊《Next.js 開發指南》、《Svelte 開發指南》、《Astro 實戰指南》。

歡迎圍觀我的“网页版朋友圈”,關注我的公眾號:冴羽(或搜索 yayujs),每天分享前端知識、AI 幹貨。


原文出處:https://juejin.cn/post/7595472747456348175


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝7   💬7   ❤️1
186
🥈
我愛JS
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付