計算選擇器的特異性
每個 CSS Selector 都有自己的特定值。序列中的每個選擇器都會增加序列的整體特異性。選擇者屬於三個不同的特異性組之一: A , B 和 c 。當多個選擇器序列選擇給定元素時,瀏覽器使用具有最高整體特異性的序列應用的樣式。
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 特異性的一個常見誤解是 A , B 和 C 組值應相互組合(a=1, b=5, c=1 => 151)。這是不是這種情況。如果是這種情況,擁有 20 個 B 組或 C 組選擇器就足以分別覆蓋單個 A 組或 B 組選擇器。這三組應被視為具體的個體水平。特異性不能用單個值表示。
建立 CSS 樣式表時,應儘可能保持最低的特異性。如果你需要將特異性提高一點來覆蓋另一種方法,那就讓它更高但儘可能低,以使其更高。你不應該有這樣的選擇器:
body.page header.container nav div#main-nav li a {}
這使得未來的變化更加困難並汙染了 css 頁面。
你可以計算出你選擇的特殊性這裡