CSS 自訂屬性:CSS 變數的宣告、取值與主題切換
以兩個連字號開頭的自訂屬性(Custom Properties)就是一般所說的 CSS 變數。同一個顏色、間距或圓角在專案裡往往出現幾十次,把它抽成一個名字之後,改一個地方就能全站生效。它與前處理器的變數最大的不同是:它活在層疊裡:會被子層 繼承、可以分區覆蓋,也能在執行時用 JavaScript 修改。
宣告與取值
宣告時用兩個連字號開頭,取值時用 var() 包起來:
:root {
--brand: #2965f1;
--radius: 8px;
}
.btn {
background: var(--brand);
border-radius: var(--radius);
}| 寫法 | 說明 |
|---|---|
--名稱: 值; | 宣告,可以寫在任何選取器上。 |
var(--名稱) | 取值,只能用在屬性值的位置。 |
var(--名稱, 預設值) | 取值並指定找不到時的替代值。 |
名稱有大小寫之分
--Brand 與 --brand 是兩個不同的變數。命名慣例上多用全小寫加連字號。
預設值
var() 的第二個參數是找不到該變數時的替代值,適合寫元件時留一個安全的底:
.card {
/* 外層有給就用外層的,沒給就用白色 */
background: var(--card-bg, #fff);
}預設值本身也可以是另一個 var(),形成多層備援:
.card {
background: var(--card-bg, var(--surface, #fff));
}它會繼承,所以能分區覆蓋
自訂屬性是 可繼承的屬性,這一點決定了它的用法:宣告在 :root 上,整份文件都拿得到;宣告在某個區塊上,就只有那個區塊與它的子層拿得到。
:root {
--text: #333;
}
/* 這一區塊裡的 --text 換成淺色,子層全部跟著變 */
.dark-panel {
--text: #f5f5f5;
}
p {
color: var(--text);
}用 JavaScript 讀寫
這是自訂屬性最實用的一點:值可以在執行時改,不必事先窮舉所有可能的樣式:
const root = document.documentElement;
// 讀取
const brand = getComputedStyle(root).getPropertyValue('--brand').trim();
// 寫入
root.style.setProperty('--brand', '#e93e30');因此像「跟著滑鼠移動的光暈」、「依後端回傳色碼換主題色」這類需求,都可以只改一個變數,樣式邏輯留在 CSS 裡。
實作:主題切換
把顏色全部抽成變數,再依 屬性選取器 換一組值,就是最常見的深色模式做法:
:root {
--bg: #ffffff;
--text: #333333;
}
[data-theme='dark'] {
--bg: #1b1b1f;
--text: #f5f5f5;
}
body {
background: var(--bg);
color: var(--text);
}document.documentElement.dataset.theme = 'dark';只要所有樣式都透過變數取值,切換主題就只是換掉那一組宣告,不必寫兩套 CSS。色彩管理的實務寫法另見 色彩表示法。
與 Sass 變數的差別
| 比較項目 | 自訂屬性 | Sass 變數 |
|---|---|---|
| 生效時機 | 瀏覽器執行時 | 編譯時就被替換掉 |
| 產出的 CSS | 變數本身還存在 | 只留下最終的值 |
| 會不會繼承 | 會,可分區覆蓋 | 不會,只看程式碼的作用範圍 |
| 能否用 JavaScript 改 | 可以 | 不行 |
| 能否用在媒體查詢條件 | 不行 | 可以 |
簡單說:值會隨狀態改變的用自訂屬性,只是為了少打字的用前處理器變數。 兩者也常一起使用,斷點與計算交給 Sass,主題與狀態交給自訂屬性,分工見 搭配 CSS 自訂屬性。
常見問題
自訂屬性和 Sass 變數差在哪?
Sass 變數在編譯時就被替換成固定值,產出的 CSS 裡不存在;自訂屬性活在瀏覽器裡,會被子層 繼承、能分區覆蓋,也能在執行時用 JavaScript 修改。需要隨狀態改變的值就該用自訂屬性。
為什麼一定要寫在 :root?
不一定。自訂屬性會被子層繼承,寫在 :root 只是讓整份文件都拿得到。若某個值只在特定區塊裡用,寫在那個區塊的選取器上更好,也能在子層重新宣告來覆蓋。
var() 可以給預設值嗎?
可以,寫成 var(--brand, #2965f1),逗號後面就是找不到該變數時的替代值。預設值也可以是另一個 var(),形成多層備援。
自訂屬性能用在媒體查詢的條件裡嗎?
不行。自訂屬性只能當屬性值使用,不能拿來組成媒體查詢的條件、選取器或屬性名稱。斷點的數值仍需要寫死,或交給前處理器的變數。