使用 CSS 自定義屬性(變數)

自定義屬性(有時稱為CSS 變數級聯變數)是由 CSS 作者定義的實體,表示將在整個文件中重複使用的特定值。它們使用 @property At規則或 自定義屬性語法(例如,--primary-color: blue;)進行設定。可以使用 CSS var() 函式(例如,color: var(--primary-color);)訪問自定義屬性。

複雜的網站擁有大量的 CSS,這通常會導致許多重複的 CSS 值。例如,在樣式表中,同一個顏色經常在數百個不同的地方使用。更改在一個地方重複多次的顏色需要搜尋替換所有規則和 CSS 檔案。自定義屬性允許在一個地方定義一個值,然後在多個其他地方引用它,以便於使用。另一個好處是可讀性和語義。例如,--main-text-color 比十六進位制顏色 #00ff00 更易於理解,尤其是在顏色用於不同上下文時。

使用兩個連字元 (--) 定義的自定義屬性受 級聯 影響,並從其父級繼承其值。@property At規則允許對自定義屬性進行更多控制,並允許您指定它是否從父級繼承其值,初始值是什麼,以及應應用的型別約束。

注意:變數在媒體查詢和容器查詢中不起作用。您可以在任何元素上任何屬性的值的任何部分使用 var() 函式。您不能將 var() 用於屬性名稱、選擇器或屬性值以外的任何內容,這意味著您不能在媒體查詢或容器查詢中使用它。

宣告自定義屬性

在 CSS 中,您可以使用兩個連字元作為屬性名稱的字首來宣告自定義屬性,或者使用 @property At規則。以下部分介紹瞭如何使用這兩種方法。

使用兩個連字元 (--) 作為字首

以兩個連字元開頭的自定義屬性以--開頭,後跟屬性名稱(例如,--my-property),以及可以是任何有效 CSS 值的屬性值。與任何其他屬性一樣,這都寫在規則集中。以下示例展示瞭如何建立自定義屬性--main-bg-color,並使用brown<named-color>

css
section {
  --main-bg-color: brown;
}

賦予規則集的選擇器(上例中的<section>元素)定義了可以使用自定義屬性的範圍。出於這個原因,一種常見的做法是在:root偽類上定義自定義屬性,以便可以在全域性範圍內引用它

css
:root {
  --main-bg-color: brown;
}

但這並非總是必須的:您可能有一些充分的理由來限制自定義屬性的範圍。

注意:自定義屬性名稱區分大小寫——--my-color將被視為與--My-color不同的自定義屬性。

使用@property規則

使用@property規則,您可以更具表達性地定義自定義屬性,並能夠將型別與屬性關聯,設定預設值以及控制繼承。以下示例建立了一個名為--logo-color的自定義屬性,它期望一個<color>

css
@property --logo-color {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}

如果您想在 JavaScript 中而不是直接在 CSS 中定義或處理自定義屬性,則可以使用相應的 API 來實現此目的。您可以在CSS 屬性和值 API頁面中瞭解有關其工作原理的資訊。

使用var()引用自定義屬性

無論您選擇哪種方法來定義自定義屬性,您都可以透過在標準屬性值的前面引用var()函式中的屬性來使用它們

css
details {
  background-color: var(--main-bg-color);
}

自定義屬性入門

讓我們從一些我們想要應用一些樣式的 HTML 開始。有一個<div>充當容器,其中包含一些子元素,有些子元素嵌套了其他元素

html
<div class="container">
  <div class="one">
    <p>One</p>
  </div>
  <div class="two">
    <p>Two</p>
    <div class="three">
      <p>Three</p>
    </div>
  </div>
  <input class="four" placeholder="Four" />
  <textarea class="five">Five</textarea>
</div>

我們將使用以下 CSS 根據元素的類來設定一些不同元素的樣式(下面未顯示一些佈局規則,以便我們可以專注於顏色)。根據它們的類,我們為元素提供了cornflowerblueaquamarine背景顏色

css
/* For each class, set some colors */
.one {
  background-color: cornflowerblue;
}
.two {
  color: black;
  background-color: aquamarine;
}
.three {
  background-color: cornflowerblue;
}
.four {
  background-color: cornflowerblue;
}
.five {
  background-color: cornflowerblue;
}

這產生了以下結果

有機會使用自定義屬性來替換這些規則中重複的值。在.container範圍內定義--main-bg-color並在多個地方引用其值後,更新後的樣式如下所示

css
/* Define --main-bg-color here */
.container {
  --main-bg-color: cornflowerblue;
}

/* For each class, set some colors */
.one {
  background-color: var(--main-bg-color);
}
.two {
  color: black;
  background-color: aquamarine;
}
.three {
  background-color: var(--main-bg-color);
}
.four {
  background-color: var(--main-bg-color);
}
.five {
  background-color: var(--main-bg-color);
}

使用 :root 偽類

對於某些 CSS 宣告,可以在級聯中更高位置宣告它,並讓 CSS 繼承解決此問題。對於非簡單的專案,這並非總是可行。透過在:root偽類上宣告自定義屬性並在整個文件中根據需要使用它,CSS 作者可以減少重複的需要

css
/* Define --main-bg-color here */
:root {
  --main-bg-color: cornflowerblue;
}

/* For each class, set some colors */
.one {
  background-color: var(--main-bg-color);
}
.two {
  color: black;
  background-color: aquamarine;
}
.three {
  background-color: var(--main-bg-color);
}
.four {
  background-color: var(--main-bg-color);
}
.five {
  background-color: var(--main-bg-color);
}

這導致的結果與上一個示例相同,但允許對所需屬性值(--main-bg-color: cornflowerblue;)進行規範宣告,如果您以後想更改整個專案的該值,這非常有用。

自定義屬性的繼承

使用兩個連字元--而不是@property定義的自定義屬性始終繼承其父級的值。以下示例演示了這一點

html
<div class="one">
  <p>One</p>
  <div class="two">
    <p>Two</p>
    <div class="three"><p>Three</p></div>
    <div class="four"><p>Four</p></div>
  </div>
</div>
css
div {
  background-color: var(--box-color);
}

.two {
  --box-color: cornflowerblue;
}

.three {
  --box-color: aquamarine;
}

根據繼承,var(--box-color)的結果如下

  • class="one"無效值,這是以這種方式定義的自定義屬性的預設值
  • class="two"cornflowerblue
  • class="three"aquamarine
  • class="four"cornflowerblue(從其父級繼承)

上面示例展示的自定義屬性的一個方面是,它們的行為與其他程式語言中的變數不完全相同。該值是在需要時計算的,而不是儲存並在樣式表的其他地方重複使用。例如,您不能設定屬性的值並期望在兄弟元素的後代規則中檢索該值。該屬性僅針對匹配的選擇器及其後代設定。

使用@property控制繼承

@property規則允許您明確指定屬性是否繼承。以下示例使用@property規則建立自定義屬性。繼承被停用,定義了<color>資料型別,並且初始值為cornflowerblue

父元素將--box-color設定為green的值,並使用--box-color作為其背景顏色的值。子元素也使用background-color: var(--box-color),如果啟用了繼承(或如果使用雙破折號語法定義),我們預計它將具有green的顏色。

html
<div class="parent">
  <p>Parent element</p>
  <div class="child">
    <p>Child element with inheritance disabled for --box-color.</p>
  </div>
</div>
css
@property --box-color {
  syntax: "<color>";
  inherits: false;
  initial-value: cornflowerblue;
}

.parent {
  --box-color: green;
  background-color: var(--box-color);
}

.child {
  width: 80%;
  height: 40%;
  background-color: var(--box-color);
}

因為在規則中設定了inherits: false;,並且在.child範圍內沒有宣告--box-color屬性的值,所以使用cornflowerblue的初始值而不是從父級繼承的green

自定義屬性的回退值

您可以使用var()函式和@property規則的initial-value為自定義屬性定義回退值。

注意:回退值不用於解決 CSS 自定義屬性不受支援時的相容性問題,因為在這種情況下,回退值將無濟於事。回退涵蓋了瀏覽器支援 CSS 自定義屬性並能夠在未定義或具有無效值的所需變數時使用不同值的情況。

var()函式中定義回退

使用var()函式,當給定變數尚未定義時,您可以定義多個回退值;這在使用自定義元素Shadow DOM時非常有用。

函式的第一個引數是自定義屬性的名稱。函式的第二個引數是可選的回退值,當引用的自定義屬性無效時,將使用該值作為替換值。該函式接受兩個引數,將第一個逗號後的所有內容都分配為第二個引數。如果第二個引數無效,則回退將失敗。例如

css
.one {
  /* Red if --my-var is not defined */
  color: var(--my-var, red);
}

.two {
  /* pink if --my-var and --my-background are not defined */
  color: var(--my-var, var(--my-background, pink));
}

.three {
  /* Invalid: "--my-background, pink" */
  color: var(--my-var, --my-background, pink);
}

如上例第二個示例(var(--my-var, var(--my-background, pink)))所示,包含自定義屬性作為回退是使用var()提供多個回退的正確方法。但是,您應該意識到此方法的效能影響,因為它需要更多時間來解析巢狀變數。

注意:回退的語法(如自定義屬性的語法)允許使用逗號。例如,var(--foo, red, blue)定義了red, blue的回退——第一個逗號和函式末尾之間的任何內容都被視為回退值。

使用@property初始值進行回退

除了使用var()之外,@property規則中定義的initial-value也可以用作回退機制。事實上,我們在@property繼承部分已經看到了這一點。

以下示例使用@property規則將--box-color的初始值設定為cornflowerblue。在規則集之後,我們希望將--box-color設定為aquamarine,但值名稱中存在拼寫錯誤。第三個<div>也是如此,我們為期望有效<color>的自定義屬性使用了2rem2remaqumarine都是無效的顏色值,因此應用了cornflowerblue的初始值

css
@property --box-color {
  syntax: "<color>";
  initial-value: cornflowerblue;
  inherits: false;
}

.one {
  --box-color: aquamarine;
  background-color: var(--box-color);
}

.two {
  --box-color: aqumarine;
  background-color: var(--box-color);
}

.three {
  --box-color: 2rem;
  background-color: var(--box-color);
}

無效的自定義屬性

每個 CSS 屬性都可以分配一個定義好的值集。如果您嘗試為屬性分配一個在其有效值集之外的值,則該值被認為是無效的

當瀏覽器遇到常規 CSS 屬性的無效值(例如,color屬性的值為16px)時,它會丟棄該宣告,併為元素分配它們在不存在該宣告的情況下具有的值。在以下示例中,我們看到常規 CSS 宣告無效時會發生什麼;color: 16px;被丟棄,而先前的color: blue規則被應用

html
<p>This paragraph is initially black.</p>
css
p {
  color: blue;
}

p {
  /* oops, not a valid color */
  color: 16px;
}

但是,在解析自定義屬性的值時,瀏覽器還不知道它們將在哪裡使用,因此它必須將幾乎所有值都視為有效。不幸的是,這些有效值可以透過var()函式表示法在可能沒有意義的上下文中使用。屬性和自定義變數可能導致無效的 CSS 語句,從而導致在計算時有效的概念。

當瀏覽器遇到無效的var()替換時,將使用該屬性的初始值或繼承值。此示例與上一個示例相同,只是我們使用自定義屬性。

瀏覽器將--text-color的值替換為var(--text-color),但16px對於color不是有效屬性值。替換後,該屬性沒有意義,因此瀏覽器分兩步處理這種情況

  1. 檢查屬性color是否可繼承。它是可繼承的,但此<p>沒有設定color屬性的任何父級。因此,我們繼續執行下一步。
  2. 將其值設定為其預設初始值,即黑色。
html
<p>This paragraph is initially black.</p>
css
:root {
  --text-color: 16px;
}

p {
  color: blue;
}

p {
  color: var(--text-color);
}

對於此類情況,@property規則可以透過允許定義屬性的初始值來防止出現意外結果

html
<p>This paragraph is initially black.</p>
css
@property --text-color {
  syntax: "<color>";
  inherits: false;
  initial-value: cornflowerblue;
}

:root {
  --text-color: 16px;
}

p {
  color: blue;
}

p {
  color: var(--text-color);
}

JavaScript 中的值

要在 JavaScript 中使用自定義屬性的值,就像使用標準屬性一樣。

js
// get variable from inline style
element.style.getPropertyValue("--my-var");

// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-var");

// set variable on inline style
element.style.setProperty("--my-var", jsVar + 4);

另請參閱