最近面試了一些求職者,我問css優先級計算規則是怎樣的?答曰ID優先級>class>元素選擇器,外聯樣式優先級低於內聯樣式,內聯樣式優先級低於行間樣式,然后就沒有然后了……,ID選擇器的優先級確實>class選擇器的優先級>元素選擇器的優先級,但是外聯樣式優先級並不一定低於內聯樣式優先級。做為一個合格的前端工程師,讓我們徹底搞清楚css優先級計算規則吧!
特殊性
css繼承是從一個元素向其后代元素傳遞屬性值所采用的機制。確定應當向一個元素應用哪些值時,瀏覽器不僅要考慮繼承,還要考慮聲明的特殊性,另外需要考慮聲明本身的來源。這個過程就稱為層疊。——《css權威指南》
上面這句話有兩個詞需要稍作解釋,“聲明”和“特殊性”。如下圖,css規則由選擇器和聲明塊組成,寫在選擇器后面大括號里的就叫聲明。
實際上,同一個元素可以使用多個規則來指定它的字體顏色,每個規則都有自己的選擇器。顯然最終只有一個規則起作用(不可能一個字既是紅色又是綠色),那么該規則的特殊性最高,特殊性即css優先級。很多同學僅僅知道選擇器優先級ID>class>元素選擇器,而不知道ID的優先級為什么大於class的優先級。那么css優先級到底是怎么計算的呢?
選擇器的特殊性值表述為4個部分,用0,0,0,0表示。
- ID選擇器的特殊性值,加0,1,0,0。
- 類選擇器、屬性選擇器或偽類,加0,0,1,0。
- 元素和偽元素,加0,0,0,1。
- 通配選擇器*對特殊性沒有貢獻,即0,0,0,0。
- 最后比較特殊的一個標志!important(權重),它沒有特殊性值,但它的優先級是最高的,為了方便記憶,可以認為它的特殊性值為1,0,0,0,0。
例如:以下規則中選擇器的特殊性分別是:
1 a{color: yellow;} /*特殊性值:0,0,0,1*/ 2 div a{color: green;} /*特殊性值:0,0,0,2*/ 3 .demo a{color: black;} /*特殊性值:0,0,1,1*/ 4 .demo input[type="text"]{color: blue;} /*特殊性值:0,0,2,1*/ 5 .demo *[type="text"]{color: grey;} /*特殊性值:0,0,2,0*/ 6 #demo a{color: orange;} /*特殊性值:0,1,0,1*/ 7 div#demo a{color: red;} /*特殊性值:0,1,0,2*/
對照下面的demo,來驗證上面幾組規則的正確與否:
<a href="">第一條應該是黃色</a> <!--適用第1行規則--> <div class="demo"> <input type="text" value="第二條應該是藍色" /><!--適用第4、5行規則,第4行優先級高--> <a href="">第三條應該是黑色</a><!--適用第2、3行規則,第3行優先級高--> </div> <div id="demo"> <a href="">第四條應該是紅色</a><!--適用第6、7行規則,第7行優先級高--> </div>
顯示效果:
分析上面的demo,要注意特殊性是怎么排序的,上面第4行和第5行規則,第4行之所以優先級比第5行高,是因為第四行特殊性值最后面是1,而第5行特殊性值最后面是0。回過頭來回答文章最開始的問題,為什么ID選擇器的優先級比類選擇器的優先級高?實際上是因為選擇器特殊性值是從左向右排序的,特殊性值1,0,0,0大於以0開頭的所有特殊性值,即便它是0,99,99,99,優先級依然比1,0,0,0要低。
前面有講到通配選擇器*的特殊性值是0,0,0,0,而元素通過父元素繼承過來的樣式是沒有特殊性值的,所以,通配選擇器定義的規則優先級高於元素繼承過來的規則的優先級。
細心的同學應該已經發現了,特殊性值中的4個0中的第一個0是給誰暗箱操作內定了嗎?是的!DOM中的行間樣式送了點紅包,於是它就牛了。行間樣式的特殊性是1,0,0,0。行間樣式的優先級比ID選擇器優先級高。
層疊
假如特殊性相同的兩條規則應用到同一個元素會怎樣?css會先查看規則的權重(!important),加了權重的優先級最高,當權重相同的時候,會比較規則的特殊性,根據前面的優先級計算規則決定哪條規則起作用,當特殊性值也一樣的時候,css規則會按順序排序,后聲明的規則優先級高,成為人生贏家,當上總經理出任CEO迎娶白富美。
我們知道a標簽有四種狀態:鏈接訪問前、鏈接訪問后、鼠標滑過、激活,分別對應四種偽類:link、:visited、:hover、:active,並且這四個偽類如果對同一個元素設置同一個屬性,那它們的聲明順序還有一定要求,一般大家都遵循“愛恨原則LVHA”(LoVe HAte),為什么是這個順序?不能是其它順序嗎?
根據css優先級計算規則,偽類的特殊性值是0,0,1,0,4個偽類的特殊性值相同,那么后面聲明的規則優先級高。當鼠標滑過a鏈接時,滿足:link和:hover兩個偽類,要改變a標簽的顏色,就必須將:hover偽類在:link偽類后面聲明;同理,當鼠標點擊激活a鏈接時,同時滿足:link、:hover、:active三種狀態,要顯示a標簽激活時的樣式(:active),必須將:active聲明放到:link和:hover之后。因此得出LVHA這個順序。這個順序能不能變?可以,但也只有:link和:visited可以交換位置,因為一個鏈接要么訪問過要么沒訪問過,不可能同時滿足,也就不存在覆蓋的問題。
###########2017-5-8補充############
有意思的是,如果某個元素class(類選擇器)的數量大於255個,不同的瀏覽器的表現不一致,包括但不限於以下瀏覽器認為class選擇器的優先級會超過id選擇器:
Firefox 52.0.2 (64 位)
IE 11
###########################
本文地址:http://www.cnblogs.com/wangmeijian/p/4207433.html
By 王美建 from 博客園 原創文章,轉載請保留署名及出處