CSS 變數 (更準確來說是 CSS 自訂屬性) 已在 Chrome 49 中推出。這些元素可用於減少 CSS 中的重複內容,以及實現強大的執行階段效果,例如切換主題,以及可能會擴充/polyfill 未來的 CSS 功能。
CSS 雜訊
設計應用程式時,常見的做法是設定一組品牌顏色,以便重複使用,讓應用程式外觀保持一致。很遺憾,在 CSS 中重複輸入這些顏色值不僅費時,也容易出錯。如果在某個時間點需要變更其中一個顏色,您可以放心大膽地使用「尋找並取代」功能,但在規模較大的專案中,這可能會變得相當危險。
最近,許多開發人員都改用 SASS 或 LESS 等 CSS 前置處理器,透過使用前置處理器變數解決這個問題。雖然這些工具大大提升了開發人員的工作效率,但它們使用的變數有個重大缺點,那就是變數是靜態的,無法在執行階段變更。在執行階段新增變數變更功能,不僅可用於動態應用程式主題設定等功能,還可為回應式設計帶來重大影響,並有機會為未來的 CSS 功能提供 polyfill。隨著 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 */
}
這項技巧特別適合用於設定使用 Shadow DOM 的 Web 元件的主題,因為自訂屬性可穿越陰影邊界。Web 元件作者可以使用備用值建立初始設計,並以自訂屬性形式公開配色「鉤子」。
<!-- 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 上查看其他瀏覽器的進度。