CSS Podcast - 003:Specificity
假設您使用的是以下 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"]
),即可將 C
元件增加 1。
在以下範例中,特異性為 (1,0,0)
#myID {
color: red;
}
其他選取器
CSS 有許多選取器。但並非所有都會增加具體性。舉例來說,:not()
擬似類別本身不會對特異性計算做出任何貢獻。
不過,傳入做為引數的選取器會加入到特異性計算中。
div:not(.my-class) {
color: red;
}
這個範例的特定性為 (0,1,1),因為它有一個類型選取器 (div
) 和一個 :not()
內部的類別。
進行隨堂測驗
測驗您對特定性評分標準的瞭解程度
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,1)
,因此總特異性為 (0,1,1)
。不會影響特異性的因素
以下是一些常見的迷思,關於影響特異性的因素。
內嵌樣式屬性
直接套用至元素 style
屬性的 CSS 不會影響特異性,因為這是級聯中評估特異性之前的不同步驟。
<div style="color: red"></div>
如要在樣式表單中覆寫這項宣告,您必須在連鎖的早期步驟中使用宣告勝出。
舉例來說,您可以將 !important
新增至其中,讓該檔案成為已授權的 !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,0,1)
) 和 1 個類別選取器 (價值 (0,0,1)
),因此總特異性為 (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;
}
這是因為兩個選取器具有相同的特異性。在這種情況下,層疊會改為使用顯示順序步驟。