CSS 變數 (更準確的 CSS 自訂屬性) 是在 Chrome 49 中到達。這些屬性有助於在 CSS 中減少重複內容,也可以發揮強大的執行階段效果,例如主題切換,且未來可能會擴充/簡化日後的 CSS 功能。
CSS 看起來十分簡潔
設計應用程式時,我們通常會設定一組品牌顏色,以便重複使用,維持應用程式的外觀。遺憾的是,在 CSS 中一再重複這些顏色值,不僅是常規做法,也容易出錯。如果有某個時候某個顏色需要改變,您可對風力做出「尋找與取代」所有事物,但對規模夠大的專案,這可能會變得危險。
近來,許多開發人員已採用 SASS 或 LESS 等 CSS 預先處理器,透過使用預先處理工具變數解決這個問題。這些工具雖已大幅提升開發人員的工作效率,但使用的變數有很大的缺點,也就是這些變數採用靜態模式,且無法在執行階段進行變更。新增在執行階段變更變數的功能,不但增加了動態應用程式主題設定等用途,還具備回應式設計的主要變形,並有機會支援日後的 CSS 功能。隨著 Chrome 49 推出,這些功能現在以 CSS 自訂屬性的形式提供。
自訂屬性簡介
自訂屬性會為 CSS 工具箱新增兩項功能:
- 可讓作者將任意值指派給具有作者選擇的名稱屬性。
var()
函式,可允許作者在其他屬性中使用這些值。
這個簡單的例子
:root {
--main-color: #06c;
}
#foo h1 {
color: var(--main-color);
}
--main-color
是作者定義的自訂屬性,其值為 #06c。請注意,所有自訂屬性開頭都是兩個破折號。
var()
函式會擷取自訂屬性值,並以自訂屬性值取代本身,因此產生的 color: #06c;
。只要自訂屬性是在樣式表中的某個位置定義,就可以供 var
函式使用。
語法一開始看起來有點奇怪。許多開發人員都會問:「為什麼不只使用 $foo
做為變數名稱?」該做法經過特別挑選,盡可能提供彈性,且未來或許允許 $foo
巨集。針對背景故事,您可以閱讀其中一個規格作者 Tab Atkins 的這篇文章。
自訂屬性語法
自訂屬性的語法相當簡單。
--header-color: #06c;
請注意,自訂屬性會區分大小寫,因此 --header-color
和 --Header-Color
是不同的自訂屬性。儘管表面值看似簡單,但允許自訂屬性的語法實際上卻是相當寬鬆的。舉例來說,以下是有效的自訂屬性:
--foo: if(x > 5) this.width = 10;
雖然這不適合當做變數,因為在任何一般屬性中都會失效,但系統可能會在執行階段讀取 JavaScript 資料並採取行動。這表示自訂屬性能夠發揮現今 CSS 預先處理工具所無法提供的各種有趣技術。因此,如果您想知道「真的,我有點 SASS,因此關心...」,那就再來一探究竟!這些並非您常用的變數。
瀑布
自訂屬性遵循標準階層式規則,因此您可以在不同等級的不同層級定義相同屬性
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
While I got red set directly on me!
<p>I’m red too, because of inheritance!</p>
</div>
也就是說,您可以在媒體查詢中使用自訂屬性來輔助回應式設計。其中一個用途可能是隨著螢幕大小增加,主要區段元素的邊界可能會擴大:
:root {
--gutter: 4px;
}
section {
margin: var(--gutter);
}
@media (min-width: 600px) {
:root {
--gutter: 16px;
}
}
請特別注意,由於目前的 CSS 預先處理工具無法定義媒體查詢內部的變數,因此無法使用上述程式碼片段。有這項能力可以帶來許多潛在機會!
您也可以透過自訂屬性,從其他自訂屬性擷取其值。設定主題時,這項功能非常實用:
:root {
--primary-color: red;
--logo-text: var(--primary-color);
}
var() 函式
如要擷取及使用自訂屬性的值,您必須使用 var()
函式。var()
函式的語法如下所示:
var(<custom-property-name> [, <declaration-value> ]? )
其中 <custom-property-name>
是作者定義的自訂屬性名稱 (例如 --foo
),而 <declaration-value>
是參照的自訂屬性無效時要使用的備用值。備用值可以是以半形逗號分隔的清單,將合併為單一值。例如,var(--font-stack,
"Roboto", "Helvetica");
定義 "Roboto", "Helvetica"
的備用項。請記住,短值 (例如邊界和邊框間距的值) 不會以半形逗號隔開,因此邊框間距的適當備用值看起來會像這樣。
p {
padding: var(--pad, 10px 15px 20px);
}
有了這些備用值,元件作者就能為元素編寫防禦樣式:
/* In the component’s style: */
.component .header {
color: var(--header-color, blue);
}
.component .text {
color: var(--text-color, black);
}
/* In the larger application’s style: */
.component {
--text-color: #080;
/* header-color isn’t set,
and so remains blue,
the fallback value */
}
這項技術特別適合使用陰影 DOM 設定網頁元件的主題,因為自訂屬性可以周遊陰影邊界。網頁元件作者可以使用備用值建立初始設計,並以自訂屬性的形式讓主題「掛鉤」。
<!-- In the web component's definition: -->
<x-foo>
#shadow
<style>
p {
background-color: var(--text-background, blue);
}
</style>
<p>
This text has a yellow background because the document styled me! Otherwise it
would be blue.
</p>
</x-foo>
/* In the larger application's style: */
x-foo {
--text-background: yellow;
}
使用 var()
時必須注意幾個事項。變數不能是屬性名稱。例如:
.foo {
--side: margin-top;
var(--side): 20px;
}
不過,這並不等同於設定 margin-top: 20px;
。反之,第二個宣告無效,並擲回為錯誤。
同樣地,如果值是由變數提供,則您無法 (一般) 建構值:
.foo {
--gap: 20;
margin-top: var(--gap)px;
}
同樣地,這並不等於設定 margin-top: 20px;
。如要建構值,則需要其他項目:calc()
函式。
使用 calc() 建構值
如果您從未使用過這項工具,calc()
函式是簡易的工具,可讓您執行計算以決定 CSS 值。所有新版瀏覽器皆支援此架構,而且可搭配自訂屬性使用以建構新的值。例如:
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px); /* niiiiice */
}
在 JavaScript 中使用自訂屬性
如要在執行階段取得自訂屬性的值,請使用已計算的 CSSStyleDeclaration 物件的 getPropertyValue()
方法。
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'
同樣地,如要在執行階段設定自訂屬性的值,請使用 CSSStyleDeclaration
物件的 setProperty()
方法。
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');
您也可以在對 setProperty()
的呼叫中使用 var()
函式,將自訂屬性的值設為參照其他自訂屬性。
/* CSS */
:root {
--primary-color: red;
--secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');
由於自訂屬性可以參照樣式表中的其他自訂屬性,因此您可以想像這種做法會如何帶來各種有趣的執行階段效果。
瀏覽器支援
目前 Chrome 49、Firefox 42、Safari 9.1 和 iOS Safari 9.3 支援自訂屬性。
操作示範
歡迎試用範例,瞭解您現在可以運用自訂屬性使用的所有有趣技巧。
其他資訊
如要進一步瞭解自訂屬性,Google Analytics (分析) 團隊的 Philip Walton 寫了他對自訂資源如此期待的原因。您可以透過 chromestatus.com 掌握其他瀏覽器的運作進度。