為什麼要寫這篇文章是因為
<style type="text/css"> body h1 { color: green; } html h1 { color: purple; } </style><body> <h1>Here is a title!</h1> </body>
上面程式碼執行結果是這樣的。按照我的理解,body在DOM中比html近,應該會按body h1中定義的綠色來顯示文字,但是恰恰相反,文字顏色是紫色的。
原因現在我當然是知道的,因為css中優先順序無視DOM樹中節點的距離遠近,就是說DOM樹中的距離不會對元素優先順序計算產生影響。如果優先順序相同,靠後的 CSS 會應用到元素上。而html h1靠後,當然是紫色了,如果調換html h1和body h1順序那就是綠色了。
以上我剛開始犯的錯誤,其實是被繼承樣式給唬住了,但是繼承的樣式是低於設定的樣式的。如果只是繼承,那離的近的當然優先順序高,比如舉個例子:
<style type="text/css"> #close{ color: green; } #further{ color: purple; } </style><body> <div id="further"> <div id="close"> <h1>Here is a title!</h1> </div> </div> </body>
不管#close和#further順序,文字都是綠色的。
接下來就係統的看看css優先順序。
一、優先順序
瀏覽器根據優先順序來決定給元素應用哪個樣式,而優先順序僅由選擇器的匹配規則來決定。
內聯》ID選擇器》偽類=屬性選擇器=類選擇器》元素選擇器【p】》通用選擇器(*)》繼承的樣式
二、優先順序計算:
上面說了,優先順序僅有選擇器決定,怎麼個計算方法呢?
a、用a表示選擇器中ID選擇器出現的次數
b、用b表示類選擇器,屬性選擇器和偽類選擇器出現的總次數。
c、用c表示標籤選擇器、偽元素選擇器出現的總次數
d、忽略通用選擇器
e、然後計算a*100+b*10+c的大小,這就是優先順序了。
權重:內聯樣式1000》id選擇器100》class選擇器10》標籤選擇器1
Note:
ID選擇器「如:#header」,Class選擇器「如:.foo」,屬性選擇器「如:[class]」,偽類「如::link」,標籤選擇器「如:h1」,偽元素「如::after」,選擇器「*」
接下來從以下幾點深入分析優先順序。
1、優先順序計算無視DOM樹中的距離
開頭說明的例子:
<!DOCTYPE html> <html> <style type="text/css"> body h1 { color: green; } html h1 { color: purple; } </style> </head> <body> <h1>Here is a title!</h1> </html>
body h1和html h1的優先順序相同。
2、偽類選擇器,屬性選擇器和class選擇器的優先順序一樣【update20170422】
偽類=屬性選擇器=類選擇器
所以後面的會覆蓋前面的。
<!DOCTYPE html> <html> <meta charset="utf-8"> <style type="text/css"> :focus { color: red; } [class] { color: blue; } .classtest { color: green; } </style> </head> <body> <div class="classtest"> 什麼顏色文字 </div> </body> </html>
如下圖類選擇器在後,所以覆蓋前面的樣式,所以文字綠色。
如下圖屬性選擇器在後,會覆蓋前面的類選擇器樣式,所以文字藍色。
focus同理,只有放後面才生效,否則會被偽類和屬性選擇器覆蓋
3、基於型別的優先順序
優先順序是根據選擇器的型別進行計算的。
舉例:屬性選擇器儘管選擇了一個ID但是在優先順序計算中還是根據型別計算,因此即使選擇的是相同的元素,但ID選擇器有更高的優先順序,所以* #foo設定的樣式生效。
<!DOCTYPE html> <html> <style type="text/css"> * #foo { color: green; } *[id="foo"] { color: purple; } </style> </head> <body> <p id="foo">I am a sample text.</p> </body> </html>
4、:not偽類不參與優先順序計
【:not】否定偽類在優先順序計算中不會被看做是偽類,但是,會把:not裡面的選擇器當普通選擇器計數。這句話有點不好理解,其實就是忽略掉:not,其他偽類(如:hover)參與CSS優先順序的計算,但是「:not」不參與計算。
舉個例子:
<!DOCTYPE html> <html> <style type="text/css"> div.outer p { color:red; } div:not(.outer) p { color: blue; } </style> </head> <body> <div class="outer"> <p>This is in the outer div.</p> <div class="inner"> <p>This text is in the inner div.</p> </div> </div> </body> </html>
該例子中,選擇器div.outer p 和選擇器div:not(.outer) p的優先順序是相同的,:not被忽略掉了,:not(.outer)中的.outer正常計數。
如果調換位置,inner元素會變成紅色
div:not(.outer) p { color: blue; } div.outer p { color:red; }
5、優先順序計算不升位
不要把權重簡單的作為10進位制數字比較其大小。
a=1的規則優先順序將永遠高於其他a=0的。
比如一個選擇器的a>0,b=0即使另外一個選擇器的a=0,b=12,c=12那麼前者的權重依然更大!!
為證明我做了一個不現實的demo
<!DOCTYPE html> <html> <meta charset="utf-8"> <style type="text/css"> #test{ /*a=1*/ color: blue } div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest div.classtest{ /*b=12*/ color:green; } </style> </head> <body> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div class="classtest"> <div id="test" class="classtest"> 什麼顏色文章 </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </body> </html>
可見文字顏色還是藍色!!
同樣有一個帶有10個id選擇器的規則,優先順序也不如內聯樣式。
總之優先順序的計算不是基於十進位制升位的,後面的數優先順序再高也不能升到前一位。
6、其他
下面再給出一個經典的例子,自己計算一下就明白了。
Examples:
* /* a=0 b=0 c=0 -> specificity = 0 */
LI /* a=0 b=0 c=1 -> specificity = 1 */
UL LI /* a=0 b=0 c=2 -> specificity = 2 */
UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */
LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */
#x34y /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
如果確實有棘手的情況,可以在Firebug中檢視優先順序。Firebug中按照優先順序排序顯示規則,將優先順序更高的規則顯示在最上面,並將被覆蓋的規則用刪除線劃掉。
三、!import
為什麼沒有把!import放在優先順序順序中,因為官方認為!import和優先順序沒一點關係。
不建議使用!import
- Never 絕不要在全站使用!import。
- Only 只在需要覆蓋全站或外部 css(例如引用的 ExtJs 或者 YUI )的特定頁面中使用
!important
- Never 永遠不要在你的外掛中使用
!important
- Always 要優先考慮使用樣式規則的優先順序來解決問題而不是
!important
選擇元素時儘量不要多選,不要放寬選擇器的範圍。因為範圍越小,越具有針對性,優先順序越高。
1、什麼場合使用!import?
使用!import的場合也是有的,但是是在沒有別的解決方案的時候。
比如需要覆蓋內聯樣式,因為內聯樣式的優先順序最高,只能用!import去覆蓋內聯樣式。
還有一種情況
<style type="text/css"> #someElement p { color: blue; } p.awesome { color: red; } </style> </head> <body> <div id="someElement"> <p class="awesome">some text</p> </div> </body>
在外層有 #someElement
的情況下,你怎樣能使 awesome
的段落變成紅色呢?這種情況下,如果不使用 !important
,第一條規則永遠比第二條的優先順序更高。這也是沒有別的辦法,如果用內聯結果只會更糟糕。
2、怎樣覆蓋已有!import規則
a、再加一條!import的css語句,將其應用到更高優先順序的選擇器(在原有基礎上新增額外的標籤、類或者ID選擇器)。
幾個更高優先順序選擇器的例子:
table td {height: 50px !important;}
.myTable td {height: 50px !important;}
#myTable td {height: 50px !important;}
b、選擇器一樣,但新增的位置在原有宣告後面。因為相同優先順序,後邊定義的宣告覆蓋前面的。
相同選擇器的例子:
td {height: 30px !important;}
td {height: 50px !important;}
四、資源連結
http://www.w3.org/TR/selectors/#specificity
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity