一篇文章帶你初步瞭解—CSS特指度

_Fatman發表於2021-01-28

CSS特指度

說明

這篇部落格在在兩臺電腦上分別完成的,故而有些截圖是Firefox,有些是Chrome,有些改動了瀏覽器的使用者樣式表,有些沒改,但不會影響閱讀,特此說明,勿怪。

CSS選擇器

單個CSS選擇器

css選擇器決定css樣式能渲染到對應的元素上。

元素選擇器:
在這裡插入圖片描述

Class選擇器:
在這裡插入圖片描述
ID選擇器:
在這裡插入圖片描述

多個CSS選擇器

瀏覽器在處理單獨的id、class和元素選擇器時如何渲染的問題很好理解,但要在兩種甚至三種不同選擇器同時作用於相同的元素的情況下,瀏覽器又該如何渲染呢?

比如3個選擇器作用在同一個元素身上的例子:

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>ICE計算公式</title>
        <style type="text/css">
            #title {
                color : blue;
            }
            .red {
                color : red;
            }
            p {
                color : brown;
            }
        </style>
    </head>
    <body>
        <p id="title" class="red">這是標題</p>
    </body>
</html>

得出結果:
在這裡插入圖片描述
當3個不同的選擇器(ID、Class、元素)同時作用於同一元素上時,瀏覽器渲染時選擇的樣式為ID選擇器宣告的樣式,這是因為ID選擇器的特指度高於Class選擇器,而Class選擇器的特指度高於元素選擇器......

那麼應該怎麼計算每個選擇器特指度,要解決這個問題,不得不提到ICE計算公式:ID-Class-Element。

ICE計算公式

關於ICE計算公式錯誤的理解

注:我在過去很長一段時間都是按照這種錯誤的思想來理解ICE計算公式的,務必注意。

關於ICE計算公式,經常看到這樣的說法(這是錯誤的):

!important ID Class Element
特指度 1000 100 10 1

Element特指度為1,class特指度為10,ID特指度為100,!important為1000。

如果按照這樣理解,是不是可以說11個class的特指度為10 * 11 === 110,它是肯定比1個Id的特指度要大的,但在我實踐後,我發現不能這樣去理解,就比如下面的例子:

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>11個class是否比1個ID特指度大</title> 
        <style type="text/css">
            #id {
                color : green;
            }
            .class1.class2.class3.class4.class5.class6.class7.class8.class9.class10.class11 {
                color: red;
            }
        </style>
    </head>
    <body>
        <p id="id" class="class1 class2 class3 class4 class5 class6 class7 class8 class9 class10 class11">p標籤</p>
    </body>
</html>

如果按照class特指度為10、id為100的邏輯來理解,110 大於 100,最後p標籤的color屬性值應該為red,但是實際情況卻是:
在這裡插入圖片描述
標籤的color屬性值為green。造成這樣結果的原因是因為不管有多少個class選擇器,Id選擇器的特指度就是比class選擇器的特指度大。就好比奧運會排名,先比較金牌,金牌數量多者排前面,數量少者排後面,在出現金牌數量相同時才會以銀牌的數量來比較。Id選擇器就好比金牌,而class選擇器就好比銀牌。當Id選擇器數量不一致時,後續操作壓根就不會去比較class選擇器,所以class選擇器的數量再多,也是無效的。

不同選擇器對應的特指度

選擇器共有:

  1. ID選擇器
  2. Class選擇器
  3. 元素選擇器
  4. 屬性選擇器
  5. 偽類選擇器
  6. 偽元素選擇器

ID選擇器

\(\color{#FF3030}{Selector Specificity: (1, 0, 0)}\)

#title {
	color : blue;
}

Class選擇器

\(\color{#FF3030}{Selector Specificity: (0, 1, 0)}\)

.red {
	color : red;
}

元素選擇器

\(\color{#FF3030}{Selector Specificity: (0, 0, 1)}\)

p {
	color : brown;
}

屬性選擇器

\(\color{#FF3030}{Selector Specificity: (0, 1, 0)}\)

[id="title"] {
    color : black;
}

偽類選擇器

\(\color{#FF3030}{Selector Specificity: (0, 1, 0)}\)

注意:p:hover的特指度為 (0, 1, 1),因為它包含了元素選擇器和偽類選擇器

p:hover {
	color: #FF00FF
}

偽元素選擇器

\(\color{#FF3030}{Selector Specificity: (0, 0, 1)}\)

注意:p::after的特指度為 (0, 0, 2),因為它包含了元素選擇器和偽元素選擇器

p::after {
    content: "元";
}

程式碼:

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>6種選擇器的特指度</title>
        <style type="text/css">
            #title {
                color : blue;
            }
            .red {
                color : red;
            }
            p {
                color : brown;
            }
            [id="title"] {
                color : black;
            }
            p:hover {
                color: yellow;
            }
            p::after {
                content: "元";
            }
        </style>
    </head>
    <body>
        <p id="title" class="red">100</p>
    </body>
</html>

其餘還有組合選擇器、分組選擇器、上下文選擇器、子元素選擇器、相鄰兄弟選擇器、後續兄弟選擇器,但是這幾種更像是選擇器的組合,它們也都是由上述6種選擇器 \(\color{#FF3030}{(ID選擇器、Class選擇器、元素選擇器、屬性選擇器、偽類選擇器、偽元素選擇器)}\)組合而成,所以它們的特指度由組成它們的選擇器的特指度相加即可獲得。

比如:

組合選擇符

\(\color{#FF3030}{Selector Specificity: (0, 2, 0)}\)

注意:此處是對Class屬性中同時含有red和indigo兩個值的元素進行宣告,它的特指度為(0, 2, 0)

.red.indigo {
    color : brown;
}

分組選擇符

\(\color{#FF3030}{Selector Specificity: (0, 0, 1)}\)

注意:此處是對p、em、strong3個元素分別進行宣告,而它們3個的特指度都為(0, 0, 1)

p , em , strong {
    color : red;
}

上下文選擇符

\(\color{#FF3030}{Selector Specificity: (0, 0, 2)}\)

注意:此處是對被包含在p元素中的em元素(\(\color{#FF3030}{此時的em元素可以為p元素的子孫元素}\))進行宣告,它的特指度為(0, 0, 2)

p em {
    color : red;
}

子元素選擇符

\(\color{#FF3030}{Selector Specificity: (0, 0, 2)}\)

注意:此處是對被包含在p元素中的em元素(\(\color{#FF3030}{此時的em元素只能為p元素的子元素}\))進行宣告,它的特指度為(0, 0, 2)

p > em {
    color : green;
}

相鄰兄弟選擇符

\(\color{#FF3030}{Selector Specificity: (0, 0, 2)}\)

注意:此處是對與p元素擁有相同父元素的em元素(\(\color{#FF3030}{此時的em元素必須緊跟在p元素的後面}\))進行宣告,它的特指度為(0, 0, 2)

p + em {
    color : red;
}

一般兄弟選擇符

\(\color{#FF3030}{Selector Specificity: (0, 0, 2)}\)

注意:此處是對與p元素擁有相同父元素的em元素(\(\color{#FF3030}{此時的em元素必須在p元素的後面,但不一定緊跟}\))進行宣告,它的特指度為(0, 0, 2)

p ~ em {
    color : red;
}

特殊情況

沒有特指度的繼承樣式

繼承樣式不考慮特指度,由下面兩個例子能說明:

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>繼承樣式不考慮特指度</title> 
        <style type="text/css">
            .yellow {
                color : yellow;
            }
        </style>
    </head>
    <body>
        <div class="yellow">
            <p>p標籤</p>
        </div>
    </body>
</html>

繼承樣式不考慮特指度-圖1
上述例子中p元素的color屬性值為red(來自使用者樣式表),繼承自div元素的color屬性值yellow被覆蓋。

(\(\color{#FF3030}{注:此瀏覽器的使用者樣式表被我修改,沒有修改過的p元素的color屬性的值應該是black。}\))

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>繼承樣式不考慮特指度</title> 
        <style type="text/css">
            .yellow {
                color : yellow;
            }
            p {
                color : green;
            }
        </style>
    </head>
    <body>
        <div class="yellow">
            <p>p標籤</p>
        </div>
    </body>
</html>

繼承樣式不考慮特指度-圖2
上述例子中p元素的color屬性值為green(來自元素選擇器),繼承自div元素的color屬性值yellow被覆蓋。

超脫特指度的 !important

!important是超脫特指度的存在

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>!important是超脫特指度的存在</title> 
        <style type="text/css">
            #id {
                color : green;
            }

            p {
                color : brown;
            }
        </style>
    </head>
    <body>
        <p id="id">p標籤</p>
    </body>
</html>

!important的特指度是最高的-圖1
修改程式碼,給元素選擇器中color屬性加上!important後:

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>!important是超脫特指度的存在/title> 
        <style type="text/css">
            #id {
                color : green;
            }

            p {
                color : brown !important;
            }
        </style>
    </head>
    <body>
        <p id="id">p標籤</p>
    </body>
</html>

!important的特指度是最高的-圖2
元素選擇器中加了!important的宣告覆蓋了ID選擇器中沒加!important的宣告。

特指度相當時 以 後宣告的屬性為準

當兩個選擇器的特指度相當時,特指度相當時 以 後宣告的屬性為準。

<!DOCTYPE html>
<html>
    <head>
        <meta name="charset" content="utf-8"/>
        <title>特指度相當時 以 後宣告的屬性為準</title> 
        <style type="text/css">
            p {
                color : green;
            }
            p {
                color : brown;
            }
        </style>
    </head>
    <body>
        <p>p標籤</p>
    </body>
</html>

在這裡插入圖片描述
後宣告的屬性覆蓋了先宣告的屬性。

總結

單個選擇器的特指度按照 !important > id選擇符 > class選擇符、屬性選擇符和偽類 > 元素選擇符和偽元素的規律排序,如果遇到組合選擇器,則按其邏輯將其拆分為單個選擇器後相加再進行判斷。如果選擇器中的宣告包含了!important,則這條屬性會覆蓋同屬性所有不包含了!important的宣告,只有在同屬性的宣告也包含!important,並且同屬性的宣告位於的選擇器的特指度大於先前的選擇器,亦或兩個選擇器的特指度相當,但同屬性的宣告位於的選擇器位於先前的選擇器之後時,才會覆蓋先前的選擇器的加了!important的屬性。

如果上面的話很難理解,可以看這裡的:
第一條:比較各自所在的選擇器的特指度,特指度越大的優先順序越高;
第二條:加了!important的宣告的屬性優先順序最高,在都加了!important的情況下按第一條為準;
第三條:在特指度相等的情況下,後宣告的優先順序大於先宣告的;
第四條:優先順序高的樣式覆蓋優先順序低的樣式。

相關文章