大多數開發者處理顏色時,就是從設計稿裡複製粘貼一個色值,然後就完事了。
但是!CSS 顏色在過去幾年裡發生了很多變化!
不僅從 Web 十六進制代碼演變成了 hsl() 函數,而且就連你熟知的 rgb() 函數也跟以前不同了!
不信我們接著往下看。
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。
除此之外,逗號現在也被視為舊語法了,對於新的顏色函數,我們甚至不能再使用逗號,只能使用新的空格語法。
.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 新增了很多顏色函數,統一用斜杠可以快速區分“顏色值”和“透明度”,看代碼時一目了然。
單位現在可選了:
.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 只有帶百分號的才會顯示顏色預覽。
相對顏色是什麼?
簡單說就是基於現有顏色生成新顏色。
我們從一個簡單的例子開始:
.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);
}
以前你想讓一個 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);
}
就像你有一張照片,以前想調整透明度要重新處理一遍,現在濾鏡一點就搞定。
我們可以快速創建基礎顏色的淺色和深色版本:
: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%); /* 紅色 */
}
一個變數搞定所有顏色變體,優雅!十分優雅!

不知道你是否實現過網站的淺色和深色主題:
: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;
}
同樣的顏色寫兩遍,一個給媒體查詢(自動切換),一個給切換按鈕。
改一次要改兩個地方,煩死了!
:root {
/* 跟隨系統偏好 */
color-scheme: light dark;
/* 一次定義,自動切換 */
--text-heading: light-dark(#000, #fff);
--text-body: light-dark(#212121, #efefef);
--surface: light-dark(#efefef, #212121);
}
light-dark(淺色, 暗色) 就這麼簡單!系統是淺色就用第一個,暗色就用第二個。
如果讓用戶手動切換主題:
: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;
}
如果某個區域必須保持固定顏色,比如某個背景圖上必須是白字:
.hero {
/* 不管全局主題怎麼變,這裡永遠是淺色主題 */
color-scheme: light;
background: url("light-background.webp");
}
讓我們直接看例子,這是一個從藍到紅的漸變:
.gradient {
--color-1: hsl(219 76 41); /* 藍色 */
--color-2: hsl(357 68 53); /* 紅色 */
background: linear-gradient(90deg, var(--color-1), var(--color-2));
}
中間會出現灰撲撲的顏色,不好看:

以前你只能手動加個中間色:
.better {
--middle: hsl(271 52 41); /* 紫色 */
background: linear-gradient(90deg, var(--color-1), var(--middle), /* 加一個中間色 */ var(--color-2));
}
是不是好看多了:

但是麻煩呀!我甚至可能需要添加兩到三個額外的色階,以確保它與原設計完全相同。
現在你可以輕鬆解決,只需要指定一個顏色空間:
.better {
/* 用 oklch 顏色空間插值,中間色更鮮豔 */
background: linear-gradient(in oklch 90deg, var(--color-1), var(--color-2));
}
就像拍照時選濾鏡,不同的顏色空間會產生不同的中間色效果。oklch 在大多數情況下效果最好。
看下效果對比:

唯一的真正問題是,不同的顏色空間可能更適合不同的漸變,所以有時確實需要花點時間摸索。
可選的顏色空間有:
oklch / lchoklab / labhwbxyzsrgb以前做彩虹要指定每一個顏色。
現在只需要:
.rainbow {
/* 從紅色繞一整圈再回到紅色,走長路徑 */
background: linear-gradient(in hsl longer hue 90deg, red, red);
}
longer hue 的意思是“走遠路”,這樣就能經過所有顏色了。

有時候客戶會拿著他們的 Logo 說:“我就要這個色,一模一樣的!”
問題是,普通的 hex、rgb() 和 hsl() 用的是 sRGB 色域,能表示的顏色有限。
這就像以前電視只能顯示幾百種顏色,然而現在的手機屏幕能顯示幾百萬種。
為了滿足客戶的需求,你可以使用 color 顏色函數,並使用 display-p3 色域。
.vibrant-green {
/* 使用 display-p3 色域,顏色更鮮豔 */
color: color(display-p3 0 1 0);
}
如果瀏覽器不支持,會自動回退到能顯示的最接近顏色,不會出錯。
你可以在 Chrome 的開發者工具查看這種顏色:

點擊色塊,它會顯示你選擇的顏色,但同時也會顯示使用 sRGB 色域的顯示器的色域限制。
建議: 除非客戶真的非常在意那個特定顏色,一般用不著。但知道有這個方案總是好的。
現在你可以更輕鬆地寫代碼了:
rgba 和 rgb,用空格代替逗號light-dark() 一次定義兩套主題最重要的是: 這些特性瀏覽器支持都很好了(除了 IE,但誰還在乎 IE 呢?)
我是冴羽,10 年筆耕不輟,專注前端領域,更新了 10+ 系列、300+ 篇原創技術文章,翻譯過 Svelte、Solid.js、TypeScript 文檔,著有小冊《Next.js 開發指南》、《Svelte 開發指南》、《Astro 實戰指南》。
歡迎圍觀我的“网页版朋友圈”,關注我的公眾號:冴羽(或搜索 yayujs),每天分享前端知識、AI 幹貨。