前端面試CSS系列——選擇器、權重計算(二)

面試問答

問:CSS選擇器權重如何計算?(或者CSS選擇器的優先級是如何計算的?)css

答:CSS權重的計算分爲四個等級a,b,c,d;其中HTML元素的style屬性中定義的聲明屬於a級,id選擇器屬於b級,屬性選擇器、class類選擇器和僞類選擇器屬於c級,類型選擇器屬於d級;四級當中a級權重值最高,d級權重值最低。權重值根據每一個級別出現的數量進行計數,每一個等級出現1次,就計數1次。權重值的比較按照a,b,c,d 四個等級計算出來的數字從高到低依次比較,若是相同等級下的值PK出結果,就不會進行後面的比較了。若是相同等級的數字相同,則繼續比較下級的數字大小。其中有些選擇器是不參與優先級的計算,其中包括:通用選擇器『*』號,否認僞類:not選擇器,組合選擇器中的子類選擇器、相鄰兄弟選擇器、普通兄弟選擇器。不過否認僞類選擇器當中的選擇器是會參與選擇器優先級計算的。包含!important的CSS聲明是特殊的存在,不參與權重值的計算,比a,b,c,d四個等級都高;在同時都包含!important時,又會根據選擇器的匹配規則計算權重值。誰的權重值高,應用誰的樣式。html

基本概念

CSS規則

CSS規則是由兩個主要的部分構成:選擇器,以及一條或多條聲明;
CSS規則前端

選擇器一般是須要改變樣式的HTML元素;聲明由一個屬性和一個值組成。屬性是但願設置的樣式屬性,每一個屬性有一個值(屬性值),屬性和值被冒號分開。面試

優先級

瀏覽器經過 優先級來判斷哪些屬性值與一個元素最爲相關,從而在該元素上應用這些屬性值。優先級是基於不一樣種類選擇器組成的匹配規則。

再重審一下,優先級是基於不一樣種類選擇器組成的匹配規則。咱們還用上面CSS規則當中的圖片示例作說明,瀏覽器

// 選擇器『p』就是計算優先級的『匹配規則』
p { font-size:14px; background:#ff0;}

ul#nav li.active a { font-size:14px; }
body.ie7 .col_3 h2~h2 { font-size:16px; }

//『ul#nav li.active a』 和 『body.ie7 .col_3 h2~h2』 是計算優先級的匹配規則

權重

權重是由匹配的選擇器中的每一種選擇器類型的數值決定的,權重計算獲得的數字越大,相對應的匹配規則優先級越高。若是一個CSS聲明在兩個優先級相等的匹配規則中定義的時候,則按照匹配規則在CSS文件當中的順序,在最後匹配規則中的CSS聲明將會被應用到元素上。post

示例字體

<div id="id" class="class">個人字體大小</div>
#id {
 font-size:18px;
}
.class {
 font-size:16px;
}

最後文字的大小是18px,根據選擇器類型的計算結果#id的值是:1,0,0;.class的值是:0,1,0。ui

計算的過程咱們先按下不表,在後面說明spa

點擊查看代碼示例code

優先級相等的匹配規則

.class{
    font-size:18px;
}
[class='class']{
    font-size:16px;
}
最後文字的大小是16px,根據選擇器類型的計算結果,.class的值是:0,1,0,[class='class']的值是:0,1,0。

點擊查看代碼示例

特異性

上面咱們說#id的計算結果是:1,0,0;.class和[class='class']的計算結果是:0,1,0。爲何會計算出這樣的值?這就是咱們要說的特異性,英文specificity。下面引用W3C官方的原文:

A selector's specificity is calculated as follows:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

選擇器的特異性計算規則以下:

  • 若是CSS聲明來自HTML元素的style屬性,而不是帶有選擇器的規則,則計數爲1,不然爲0;(在HTML中,元素的style屬性值是樣式表規則。這些規則沒有選擇器;元素style屬性定義的樣式規則,在特異性計算當中用a表示,因此一般在HTML中,元素的style屬性定義的樣式表規則的特異性表示爲:a=1,b=0,c=0,d=0。)
  • 計算選擇器中id屬性的數量,用b表示
  • 計算選擇器中的其它屬性(包括class屬性)和僞類的數量,用c表示
  • 計算選擇器中元素名稱和僞元素的數量,用d表示

『特異性』這個詞真的很是很是很差理解,根據語義徹底不明白說的是什麼意思,爲了更好的理解,我用『權重值』來表示『特異性』。

計算示例

*              {}  /* a=0 b=0 c=0 d=0 -> 權重值 = 0,0,0,0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> 權重值 = 0,0,0,1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> 權重值 = 0,0,0,2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> 權重值 = 0,0,0,2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> 權重值 = 0,0,0,3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> 權重值 = 0,0,1,1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> 權重值 = 0,0,1,3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> 權重值 = 0,0,2,1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> 權重值 = 0,1,0,0 */
 style=""          /* a=1 b=0 c=0 d=0 -> 權重值 = 1,0,0,0 */
注意:當ID選擇器被當作屬性選擇器使用的時候,好比 [id='id'],權重值的計算會把它當中C級來計算

權重值計算規則

權重值 = a*num,b*num,c*num,d*num;

權重值的計算網上還有一種比較常見的說法:style屬性定義的樣式權重值是1000,一個id選擇器權重值是100,一個屬性和僞類選擇器權重表示爲10,一個元素名稱和僞元素的權重值爲1。好比:
權值的計算

按照咱們說的權重值計算規則,其實圖片中的total value 的值應該表示爲:0,1,1,3。直接用數字113表示只是爲了方便記憶,但選擇器優先級的比較卻不能經過數字來進行比較。好比:兩條匹配規則,一個是11個屬性選擇器,另外一個是1個id選擇器,他們權重值進行比較時:

11個屬性選擇器獲得的結果是110,二ID選擇器獲得的寄過是100。很明顯『11個屬性選擇器』獲得的數字值最大,是否是它的優先級最高呢。咱們實驗下:

HTML文本

<div id='id' class='c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11'>
    應用誰的樣式
</div>

CSS樣式

#id {
    background:red;
}

[id='id'][class~='c1'].c1.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11{
 background:yellow;
}

你也能夠點擊示例親自試一下

權重值的比較

當兩個權值進行比較的時候,是從A到D逐級將等級位上的權重值(如 權值 1,0,0,0 對應--> A,B,C,D)來進行比較的,而不是簡單的 1000個數 + 100個數 + 10個數 + 1個數 的總和來進行比較的,換句話說,低等級的選擇器,個數再多也不會越等級超太高等級的選擇器的優先級的;請看下圖:
權重值的比較
總結

  1. 權重值的比較按照a,b,c,d的等級逐級比較,若是同等級的值相同,繼續向下級比較
  2. 若是計算獲得的權重值相同,那麼哪條匹配規則在最後,就應用誰的CSS聲明
  3. !important 是超越上述權重值計算規則以外的,優先級最高。

不參與計算的選擇器

並非全部的選擇器都參與權重值的計算規則,有些是不參與的,其中包括:

  1. 通用選擇器『*』
  2. 否認僞類選擇器『:not』
  3. 組合選擇器『+,~,>』
否認僞類選擇器: :not(), 雖然它自己是不計權重的, 可是寫在它裏面的 css selector 是須要計算權重的.

!important

!important是特殊的存在,!important 是不在 css 選擇器的權重計算範圍內的, 而它之因此能讓 css 選擇器生效是由於瀏覽器在碰見 !important 時會進行特殊的判斷。當多個 !important 須要進行比較時, 會先計算其權重再進行比較。一般來講, 不提倡使用 !important。不過當咱們須要覆蓋style屬性中定義的樣式時,能夠選擇使用!important

其它說明

  • 優先級計算無視DOM樹中的距離;好比:html pbody p的權重值同樣,誰寫在後面應用誰的CSS聲明
  • 僞類選擇器,屬性選擇器,class選擇器的權重值同樣

參考

計算選擇器的特異性CSS2

分配屬性值、級聯、繼承CSS22

計算選擇器的特異性

前端雜談:css權重

優先級

CSS層疊

CSS繼承

深刻理解CSS選擇器優先級

相關文章
相關標籤/搜索