計算選擇器的特異性

每個 CSS Selector 都有自己的特定值。序列中的每個選擇器都會增加序列的整體特異性。選擇者屬於三個不同的特異性組之一: ABc 。當多個選擇器序列選擇給定元素時,瀏覽器使用具有最高整體特異性的序列應用的樣式。

A 組是最具體的,其次是 B 組,最後是 C 組。

通用選擇器(*)和組合器(如 >~)沒有特異性。

示例 1:各種選擇器序列的特異性

#foo #baz {}      /* a=2, b=0, c=0 */

#foo.bar {}       /* a=1, b=1, c=0 */

#foo {}           /* a=1, b=0, c=0 */

.bar:hover {}     /* a=0, b=2, c=0 */

div.bar {}        /* a=0, b=1, c=1 */

:hover {}         /* a=0, b=1, c=0 */

[title] {}        /* a=0, b=1, c=0 */

.bar {}           /* a=0, b=1, c=0 */

div ul + li {}    /* a=0, b=0, c=3 */

p::after {}       /* a=0, b=0, c=2 */

*::before {}      /* a=0, b=0, c=1 */

::before {}       /* a=0, b=0, c=1 */

div {}            /* a=0, b=0, c=1 */

* {}              /* a=0, b=0, c=0 */

示例 2:瀏覽器如何使用特異性

想象一下以下的 CSS 實現:

#foo {
  color: blue;
}

.bar {
  color: red;
  background: black;
}

這裡我們有一個 ID 選擇器,它將 color 宣告為藍色,一個類選擇器將 color 宣告為紅色,將 background 宣告為黑色

兩個宣告將選擇 ID 為 #foo.bar 類的元素。ID 選擇器具有 A 組特異性,類選擇器具有 B 組特異性。ID 選擇器超過任意數量的類選擇器。因此,來自 #foo 選擇器的 color:blue; 和來自 .bar 選擇器的 background:black; 將應用於該元素。ID 選擇器的更高特異性將導致瀏覽器忽略 .bar 選擇器的 color 宣告。

現在想象一下不同的 CSS 實現:

.bar {
  color: red;
  background: black;
}

.baz {
  background: white;
}

這裡我們有兩個類選擇器; 其中一個宣稱 color紅色background黑色,另一個宣稱 background白色

具有 .bar.baz 類的元素將受到這兩個宣告的影響,但是我們現在遇到的問題是 .bar.baz 具有相同的 B 組特異性。CSS 的級聯性質為我們解決了這個問題:由於 .baz .bar 之後定義的,我們的元素最終得到了來自 .bar紅色 color,但是來自 .baz白色 background

例 3:如何操作特異性

可以操作上面示例 2 中的最後一個片段,以確保使用 .bar 類選擇器的 color 宣告而不是 .baz 類選擇器的宣告。

.bar {}        /* a=0, b=1, c=0 */
.baz {}        /* a=0, b=1, c=0 */

實現這一目標的最常見方法是找出可以應用於 .bar 選擇器序列的其他選擇器。例如,如果 .bar 類僅應用於 span 元素,我們可以將 .bar 選擇器修改為 span.bar。這將給它一個新的 C 組特異性,它將覆蓋 .baz 選擇器的缺乏:

span.bar {}    /* a=0, b=1, c=1 */
.baz {}        /* a=0, b=1, c=0 */

然而,可能並不總是能夠找到在使用 .bar 類的任何元素之間共享的另一個公共選擇器。因此,CSS 允許我們複製選擇器以增加特異性。我們可以使用 .bar.bar 代替 .bar(參見選擇器的語法,W3C 推薦標準 )。這仍然選擇具有 .bar 類的任何元素,但現在具有組 B 特異性的兩倍 :

.bar.bar {}    /* a=0, b=2, c=0 */
.baz {}        /* a=0, b=1, c=0 */

!important 和內聯樣式宣告

樣式宣告中的 !important 標誌和 HTML style 屬性宣告的樣式被認為具有比任何選擇器更高的特異性。如果存在這些,它們影響的樣式宣告將否決其他宣告,無論它們的特殊性如何。也就是說,除非你有多個宣告包含適用於同一元素的同一屬性的 !important 標誌。然後,正常的特異性規則將適用於那些相互引用的屬性。

因為它們完全覆蓋了特異性,所以在大多數使用案例中都不贊成使用 !important。人們應該儘可能少地使用它。為了長期保持 CSS 程式碼的有效性和可維護性,增加周圍選擇器的特異性幾乎總是比使用 !important 更好。

!important 並不令人討厭的罕見例外之一是在實現通用助手類時,如 .hidden.background-yellow 類,它們應始終在任何遇到的地方覆蓋一個或多個屬性。即便如此,你還需要知道自己在做什麼。在編寫可維護的 CSS 時,你想要的最後一件事就是在整個 CSS 中使用 !important 標誌。

最後一點

關於 CSS 特異性的一個常見誤解是 ABC 組值應相互組合(a=1, b=5, c=1 => 151)。這是不是這種情況。如果是這種情況,擁有 20 個 B 組或 C 組選擇器就足以分別覆蓋單個 A 組或 B 組選擇器。這三組應被視為具體的個體水平。特異性不能用單個值表示。

建立 CSS 樣式表時,應儘可能保持最低的特異性。如果你需要將特異性提高一點來覆蓋另一種方法,那就讓它更高但儘可能低,以使其更高。你不應該有這樣的選擇器:

body.page header.container nav div#main-nav li a {}

這使得未來的變化更加困難並汙染了 css 頁面。

你可以計算出你選擇的特殊性這裡