CSS Podcast - 003:特異性
假設您使用下列 HTML 和 CSS:
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
這裡有兩項規則都以相同元素為目標。 每項規則都包含要設定按鈕顏色的宣告: 一個嘗試將按鈕塗成紅色,另一個則嘗試塗成藍色。 哪個宣告會套用至元素?
瞭解 CSS 權重演算法,是瞭解 CSS 如何在相互競爭的宣告之間做出決定的關鍵。
特異性是層疊樣式表中的一個獨立階段,我們在上一個單元中介紹了層疊樣式表。
優先權評分
來源中的每個選取器規則都會獲得分數。您可以將特異性視為總分,每個選取器類型都會為該分數加分。 系統會採用最明確規則的宣告。
在實際專案中,特異性是確保您預期套用的 CSS 規則確實套用,同時一般會保持低分,以避免複雜性。特異性應盡量符合需求,而非追求最高特異性。日後可能需要套用一些真正更重要的 CSS。如果選擇最高精確度,這項工作就會變得非常困難。
優先權不是十進位數字,而是由三個元件組成的三元組:A、B 和 C。
A:類似 ID 的具體性B:類似類別的特異性C:類似元素的特殊性
這通常以 (A,B,C) 符號表示。例如:(1,0,2)。替代的 A-B-C 標記也很常用。
如何比較特異性
比較特定性時,會依序比較三個元件:A 值較大的特定性較明確;如果兩個 A 值相同,則 B 值較大的特定性較明確;如果兩個 B 值也相同,則 C 值較大的特定性較明確;如果所有值都相同,則兩個特定性相等。
舉例來說,(1,0,0) 的具體程度高於 (0,4,3),因為 (1,0,0) 中的 A 值 (即 1) 大於 (0,4,3) 中的 A 值 (即 0)。
選取器會影響明確性
特異性三元組的每個部分都以 0 開頭,因此預設特異性為 (0,0,0)。選取器的每個部分都會提高特定性,並根據選取器類型,遞增 A、B 或 C 的值。
通用選取器
通用選取器 (*) 不會增加明確性,因此其值會維持 (0,0,0) 的初始明確性。
* {
color: red;
}
元素或虛擬元素選取器
元素 (類型) 或虛擬元素選取器會新增類似元素的特殊性,並將 C 元件遞增 1。
下列範例的整體特殊性為 (0,0,1)。
類型選取器
div {
color: red;
}
虛擬元素選取器
::selection {
color: red;
}
類別、虛擬類別或屬性選取器
類別、虛擬類別或屬性選取器會新增類似類別的特殊性,將 B 元件遞增 1。
以下範例的特異性為 (0,1,0)。
類別選取器
.my-class {
color: red;
}
虛擬類別選取器
:hover {
color: red;
}
屬性選取器
[href='#'] {
color: red;
}
ID 選取器
ID 選取器會新增類似 ID 的特殊性,只要使用 ID 選取器 (#myID) 而非屬性選取器 ([id="myID"]),A 元件就會遞增 1。
在以下範例中,特異性為 (1,0,0)
#myID {
color: red;
}
其他選取器
CSS 有許多選取器。並非所有屬性都會增加明確性。
舉例來說,:not() 虛擬類別本身不會為特殊性計算新增任何內容。
:not() 虛擬類別的特殊性會由以半形逗號分隔的選取器引數中,最特定選取器的特殊性取代;提供的特殊性與寫入 :not(:is(argument)) 時相同。
div:not(.my-class) {
color: red;
}
:is() 虛擬類別本身也不會加入特異性計算。與 :not() 類似,它會採用最明確引數的明確性。
:is(h1, h2, h3) {
color: blue;
}
這個範例只有一種選取器 (type),因此特異性為 (0,0,1)。
新增 id 後,具體程度會提高至 (1,0,0)。
:is(h1, h2, h3, #my-heading) {
color: blue;
}
:where() 虛擬類別則不同。無論任何引數的具體程度為何,一律具有 (0,0,0) 的具體程度。
:where(h1, h2, h3, #my-heading) {
color: blue;
}
使用 :where() 套用的低特異性樣式可讓您稍後在 CSS 樣式表中使用基本選取器覆寫這些樣式:
:where(#my-content) {
color: red;
}
p {
color: blue;
}
即使 :where() 的引數清單中有 id,但其特殊性仍只有 (0, 0, 0),因此基本 p 選擇器會覆寫該引數,而文字會是 blue。
隨堂測驗
測試您對權重分數的瞭解程度
「a[href="#"]」的具體程度為何?
(0,0,1)a 價值 (0,0,1),但 [href="#"] 價值 (0,1,0)。(0,1,0)a 價值 (0,0,1),但 [href="#"] 價值 (0,1,0)。(0,1,1)a 的值為 (0,0,1),[href="#"] 的值為 (0,1,0),因此總特異性為 (0,1,1)。不會影響特異性的因素
以下列出幾個常見的誤解,有助於瞭解影響具體程度的因素。
內嵌樣式屬性
直接套用至元素 style 屬性的 CSS 不會影響特殊性,因為這是層疊中的不同步驟,會在評估特殊性之前進行。
<div style="color: red"></div>
如要從樣式表內覆寫這項宣告,您必須在層疊的先前步驟中,取得宣告的優先權。
舉例來說,您可以將 !important 加入其中,讓它成為「Authored !important」來源的一部分。
!important 項聲明
CSS 宣告結尾的 !important 不會影響特異性
但會將宣告放在不同的來源,
也就是「撰寫的 !important」。
在下列範例中,.my-class 的特異性與 !important 宣告是否勝出無關。
.my-class {
color: red !important;
color: white;
}
如果兩個宣告都是 !important,則特異性會再次發揮作用,因為來自層疊的原始步驟尚未判斷出勝出者。
.branding {
color: blue !important;
}
button {
color: red !important;
}
情境中的優先權
使用複雜或複合選取器時,選取器的每個部分都會加總為特定性。請參考以下 HTML 範例:
<a class="my-class another-class" href="#">A link</a>
這個連結有兩個類別。
下列 CSS 中的規則明確度為 (0,0,1):
a {
color: red;
}
如果您在選取器中參照其中一個類別,現在的明確度為 (0,1,1):
a.my-class {
color: green;
}
將其他類別新增至選取器,現在的明確度為 (0,2,1):
a.my-class.another-class {
color: rebeccapurple;
}
將 href 屬性新增至選取器,現在的明確度為 (0,3,1):
a.my-class.another-class[href] {
color: goldenrod;
}
最後,在所有這些項目中加入 :hover 虛擬類別,選取器最終會具有 (0,4,1) 的特異性:
a.my-class.another-class[href]:hover {
color: lightgrey;
}
隨堂測驗
測試您對權重分數的瞭解程度
下列哪個選取器的特殊性為 (0,2,1)?
article > section(0,0,2)。article.card.dark(0,2,1)。article:hover a[href](0,0,1))、1 個屬性選取器 (值為 (0,1,0)) 和 1 個類別選取器 (值為 (0,1,0))。因此,這個選取器的總特異性為 (0,2,2)。以實用方式提高精確度
假設您有類似這樣的 CSS:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
HTML 如下所示:
<button class="my-button" onclick="alert('hello')">Click me</button>
按鈕的背景為灰色,因為第二個選取器具有(0,1,1) 的特異性。這是因為它有一個類型選取器 (button),即 (0,0,1),以及一個屬性選取器 ([onclick]),即 (0,1,0)。
先前的規則 .my-button 等於 (0,1,0),因為它有一個類別選取器,特異性比 (0,1,1) 低。
如要提升這項規則的優先順序,可以重複類別選取器,如下所示:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
現在按鈕會加上藍色背景,因為新的選取器會取得 (0,2,0) 的特定性
如果特異性相同,則會回溯至層疊的下一個步驟
現在繼續使用按鈕範例,將 CSS 切換為以下內容:
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
按鈕的背景為灰色,因為兩個選取器的特異性相同,都是 (0,1,0)。
如果切換來源順序中的規則,按鈕就會變成藍色。
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
這是因為兩個選取器的特異性相同。 在此情況下,層疊會回溯至顯示順序步驟。