前言
配圖是小孩疊的積木,覺得剛好符合這個主題,所以就拿來做封面了哈。
什麼是CSS權重?
CSS權重
,我們可以簡單理解為CSS優先順序
。來看下MDN官網對優先順序
的描述:
瀏覽器通過優先順序來判斷哪一些屬性值與一個元素最為相關,從而在該元素上應用這些屬性值。優先順序是基於不同種類選擇器組成的匹配規則。
我們通過一個小例子來加深理解下:
<p class="text" id="text">我是一段簡單的文字。</p>
複製程式碼
.text {
color: red; // 紅色
}
#text {
color: blue; // 藍色
}
複製程式碼
執行後,可以看到p
標籤文字的顏色為藍色
。
那麼為什麼會是藍色的?這就是CSS權重
來決定的。決定最終用哪個樣式作用到該p
標籤上。
上面程式碼說明:ID
選擇器的權重大於類選擇器
,所以CSS權重
跟選擇器的分類密切相關。如果您對CSS選擇器
還不太瞭解,或者說不太清楚CSS有哪些選擇器,個人建議你先閱讀以下幾篇文章,這樣更有助於幫助你閱讀本文後面的內容:
選擇器的型別
- 型別選擇器(例如,
h1
)和偽元素選擇器(例如,:before
) - 類選擇器(例如,
.example
)和屬性選擇器(例如,[type="radio"]
),偽類選擇器(例如,:hover
) - ID選擇器(例如,
#example
)
上面列表中,選擇器型別的優先順序是遞增的。
萬用字元選擇器(*
)和關係選擇器(~
,+
,>
,)和否定偽類
:not()
對優先順序沒有影響。(但是在:not()
內部宣告的選擇器會影響優先順序)。
給元素新增內聯樣式
(例如,style="font-weight: bold;"
)總會覆蓋外部樣式表的任何樣式,因此可看作是具有最高的優先順序。除了一個例外的規則!important
,這個看下MDN
官網對其的詳細講解。
CSS權重概述
權重
決定了你的CSS規則怎麼樣被瀏覽器解析直到生效權重
決定了哪一條規則會被瀏覽器應用到元素上- 每個選擇器都有自己的權重
- 如果兩個選擇器作用到同一元素上,則權重高者生效
- 如果兩個選擇器權重相同,則最後定義的規則被計算到權重中(後面定義的CSS規則權重要更大,會覆蓋前面的CSS規則)
選擇器權重的計算
除了上面通過選擇器的型別,我們可以大概知道誰的權重值更高,但是如果想更深入的理解CSS權重
和更好的利用CSS權重
來編寫更加靈活的樣式,我們還需要明白選擇器的權重是如何計算的。
- A:如果樣式是寫在標籤的
style
屬性中(內聯樣式),這A=1,否則,A=0。對於內聯樣式,由於沒有選擇器,所以B、C、D的值都為0,即A=1,B=0,C=0,D=0(簡寫為1,0,0,0,下同)。 - B:計算選擇器中ID的數量。(例如,#header這樣的選擇器,計算為0,1,0,0)。
- C:計算選擇器中類選擇器、屬性選擇器和偽類的數量。(例如.logo[id='site-logo']這樣的選擇器,計算為0,0,2,0)
- D:計算選擇器中型別選擇器和偽元素的數量。例如(p:first-letter這樣的選擇器,計算為0,0,0,2)
- 忽略通用選擇器
CSS2規範中給出的一些例子:
* {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */
複製程式碼
根據這樣的定義,很多網站的文章簡單的把CSS權重
歸納為:內聯樣式的權重值是1000,ID選擇器的權重是100,class選擇器的權重值是10,標籤選擇器的權重值是1,整條規則的權重值相加得到整個樣式規則的權重值,數值越大權重就越高。
還有一個我們應該很熟悉的公式:important > 內聯 > ID > 類|屬性|偽類 > 標籤|偽元素 > 萬用字元 > 繼承
。
大多數情況下,按照這樣的理解得出的結論是沒問題的,但是遇到下面的情況就出現問題了:
/* 樣式一 */
body header div nav ul li div p a span em { color: red; }
/* 樣式二 */
.count { color: blue; }
複製程式碼
按照錯誤的計算方法,樣式一的權重值為11,樣式二的權重值為10,如果這兩條規則作用於同一個元素,則元素的文字顏色應該為紅色,而實際上卻是藍色。
我們把上面兩條規則應用到一個em
元素上,在瀏覽器中來看個究竟:
<em class="count">我最終的文字顏色是?</em>
複製程式碼
可以看到最終的顏色是:藍色
。
權重值的比較
為什麼會出現例子中的情況,這就涉及到權重值的比較規則,我們一起來了解下。
按照四組正確的計算方法,上面例子中樣式一的權重值應該是0,0,0,11
,樣式二的權重值是0,0,1,0
。
按照規範,計算權重值時,A,B,C,D四組值,從左到有,分組比較,如果A相同,比較B,如果B相同,比較C,如果C相同,比較D,如果D相同,後定義的優先。
樣式一和樣式二的A,B相同,所以比較C,而樣式二的C大於樣式一,所以,不管D值如何,樣式二的權重都大於樣式一。這才是正確的計算權重的方法。
舉個更容易理解的栗子哈:1張百元大鈔大,還是99張1元的加起來大?明白了吧,哈哈~
例外的!important
規則
在按照ABCD四組計算比較之外,還可以對某一個屬性使用!important
規則。需要特別注意的是,這裡的“!”與其在程式語言中的意義恰好相反,不是代表“不重要”二是代表“很重要”。
CSS2 規範中規定:!important 用於單獨指定某條樣式中的單個屬性。對於被指定的屬性,有 !important 指定的權重值大於所有未用 !important 指定的規則。
我們來看個例子:
<header id="header">
<nav>
<ul>
<li class="current has-important">首頁</li>
</ul>
</nav>
</header>
複製程式碼
/* 樣式一 */
#header nav ul li.current {
color: red;
font-weight: bold;
}
/* 樣式二 */
li.has-important {
color: blue !important;
font-weight: normal;
}
複製程式碼
就整條規則而言,樣式一的權重值為0, 1, 1, 3
,而樣式二的權重值僅為0, 0, 1, 1
。所以應用於相同元素時,應該樣式一生效。但是對於color
屬性,由於在樣式二中,用!important
做了指定,因此color
將應用樣式二的規則,而font-weight
還是用樣式一的規則。在瀏覽器看下實際效果:
那如果多條規則中都對同一屬性指定了!important
呢?我們再來簡單寫個例子測試下:
<div id="multipleImportant" class="multiple-important">
如果多條規則中都對同一屬性指定了`!important`,誰生效?
</div>
複製程式碼
/* 樣式一 */
#multipleImportant {
color: red !important;
}
/* 樣式二 */
.multiple-important {
color: blue !important;
}
複製程式碼
其實這時候!important
的作用已經相互抵消了,依然按照ABCD四組計算來比較。很明顯,id選擇器的權重要比class選擇器權重高,所以最終樣式一生效,文字顯示紅色
。
但是,使用!important
是一個壞習慣,我們應該儘量避免。因為這破壞了樣式表中固有的級聯規則,使得除錯bug變得更加困難了。
來自MDN上的一些經驗法則:
- 一定要優先考慮使用樣式規則的優先順序來解決問題而不是
!important
- 只有在需要覆蓋全站或外部CSS(例如引用的 ExtJs 或者 YUI )的特定頁面中使用
!important
- 永遠不要在全站範圍的css上使用
!important
- 永遠不要在你的外掛中使用
!important
取而代之,你可以:
- 更好的利用CSS級聯屬性
- 使用更具體的規則。在您選擇的元素之前增加一個或多個元素,使選擇器變得更加具體,並獲得更高的優先順序。
比如下面這個例子:
<div id="test">
<span>Text</span>
</div>
複製程式碼
div#test span { color: green }
span { color: red }
div span { color: blue }
複製程式碼
上面例子中,無論你CSS語句的順序是什麼樣的,文字都會是綠色的(green),因為這一條規則是最具有針對性,優先順序最高的。(同理,無論語句順序怎麼樣,藍色(blue)的規則都會覆蓋紅色的規則(red))。
什麼情況下可以使用!important
A)一種情況
- 你的網站上有一個設定了全站樣式的CSS檔案
- 同時你(或是你同事)寫了一些很差的內聯樣式
在這些情況下,你就可以在你全域性的CSS檔案中寫一些!important
的樣式來覆蓋掉那些直接寫在元素上的行內樣式。
活生生的例子比如:一些寫得很糟糕的jQuery外掛裡面使用的內聯樣式。
B)另一種情況
#someElement p { color: blue; } p.awesome { color: red; }
複製程式碼
在外層有#someElement
的情況下,你怎樣能使awesome
的樣式變成紅色呢?如果不使用!important
,第一條的規則永遠比第二條規則權重更高。
怎樣覆蓋!important
A)很簡單,只需再新增一條帶!important
的CSS規則,要麼給這個選擇器更高的優先順序(新增一個標籤,ID或類);或是新增一樣的選擇器,把它的位置放在原有宣告的後面。
一些擁有更好的優先順序的例子,從上到下,優先順序是遞增的:
table td { height: 50px !important; }
.myTable td { height: 50px !important; }
#myTable td { height: 50px !important; }
複製程式碼
B)或者使用相同的選擇器,但是置於已有的樣式之後:
td { height: 50px !important; }
複製程式碼
C)或乾脆改寫原來的規則,以避免使用!important
關於inherit
除了直接指定到元素上的樣式規則外,每個屬性值還有一個可能為inherit
(繼承)的值。表示元素的樣式屬性繼承自父元素,與父集元素的定義一致。
看個例子:
<ul class="list">
<li class="item">
<span>文字文字文字</span>
</li>
</ul>
複製程式碼
.list .item { color: red; }
複製程式碼
上面的例子中,我們並沒有給span
新增color
屬性,但是span
的文字顏色會是紅色的,這就是因為span
的color
屬性預設值為inherit
。
對於inherit
屬性,只需要記住一點:繼承而來的值權重永遠低於明確指定到元素的定義。只有當一個元素的某個屬性沒有被直接指定時,才會繼承父級元素的值。
再看個例子:
<ul class="list">
<li class="item">
<span>文字文字文字</span>
</li>
</ul>
複製程式碼
.list .item { color: red; }
span { color: blue; }
複製程式碼
上面的例子中,第一條規則按照ABCD四組計算的權重為0,0,2,0
;第二條規則的權重為0,0,0,1
;雖然第一條規則的權重更高,但是它是針對li
元素的直接指定,並不是針對span
元素定義的,所以計算span
的color
屬性權重值時,實際上就是inherit
的紅色與直接指定的藍色對比。按照規則,只要有直接指定的值(藍色),就不會再繼承父級元素的值(紅色),所以最終span
的文字顏色為藍色
。
關於inherit
規則,最典型的場景就是連結文字的顏色。通常瀏覽器自帶的樣式表都有針對a
標籤的顏色及下劃線的直接指定,所以我們自定義的樣式表中對a
標籤的父級指定color
屬性和text-decoration
屬性,通常是不會起作用的。我們來看個例子:
<p class="txt">
<a href="#">父級元素設定的color和text-decoration對我不起作用</a>
</p>
複製程式碼
.txt {
color: red;
text-decoration: none;
}
複製程式碼
我們在瀏覽器可以看到,儘管我們給a
標籤的父級p
設定了顏色紅色和去除下劃線,a
標籤依然是藍色的和帶下劃線的。
即使你給它們都加上!important
,也無效。
但是我們可以通過下面的reset來改變這一點:
a {
color: inherit;
text-decoration: inherit;
}
.txt {
color: red;
text-decoration: none;
}
複製程式碼
再來看下效果:
可以看到,父級設定的樣式生效了。由於我們的樣式表對a
標籤直接指定了color
和text-decoration
屬性值,覆蓋了瀏覽器的預設樣式,所以在沒有特別指定a
標籤的顏色和下劃線定義的前提下,會從父級元素p
繼承,因此連結會顯示紅色和沒有下劃線。
注意:inherit
在 CSS1 規範中並未定義,所以 IE6, IE7 以及 IE8 的 QuirksMode 不支援。
有意思的a標籤
我們直接看例子:
<a href="#">滑鼠劃入時,我的顏色是?</a>
複製程式碼
a:hover {
color: red;
}
a:link {
color: blue;
}
複製程式碼
我們希望的效果是滑鼠移入a
標籤的時候,文字變成紅色的。實際上呢?仍然是藍色。
為什麼會這樣呢?
其實,a
標籤的四個偽類(:link
、:hover
、active
、visited
)的優先順序是一樣的,所以這時候就看他們在樣式檔案中的順序了,後面的會覆蓋前面的,這回你知道為什麼了吧。
為了避免出現這樣的情況,我們在寫a
標籤的偽類的時候,要注意它們的順序,遵循::link
、:visited
、:hover
、:active
。
在網上看到的例子
之前在其他網站上,看到這樣一個例子,大概是這樣的:
<p class="blue red">我的顏色是?</p>
<p class="red blue">我的顏色是?</p>
複製程式碼
.red {
color: red;
}
.blue {
color: blue;
}
複製程式碼
問:兩個p標籤的文字顏色分別是什麼?
答案是:都是藍色的
這邊要注意的是:class中的類名的順序並不會影響樣式的優先順序,而是由它們在樣式檔案中的先後順序決定的,後面定義的優先順序更高。
總結
- 權重的大小跟選擇器的型別和數量有關
- 樣式的優先順序跟樣式的定義順序有關,後面的覆蓋前面的
- 一條樣式規則的整體權重值包含四個獨立的部分:[A,B,C,D]
- A表示內聯樣式,只有1或0兩個值
- B表示選擇器中ID的數量
- C表示選擇器中類、屬性、偽類選擇器的數量
- D表示選擇器中偽元素及標籤的數量
- 比較時,從低位到高位(從A到D)分別比較,高位相同時才比較低位
- 標籤選擇器的權重永遠都比一個類選擇器的權重低,無論有多少個,除非使用
!important
- 有
!important
標記指定的屬性權重值最高;多次指定時,相互抵消;應儘量減少!important
的使用 inherit
而來的屬性定義,優先順序低於任何直接指定的屬性值
最後
這篇文章斷斷續續寫了好多天,但也算比較詳細,自己也比較深入的學習了CSS權重相關的知識。
感謝耐心讀完,如果還有什麼疑問或者建議,可以多多交流。
好了,本文到此結束,希望對你有幫助 :)
參考
developer.mozilla.org/zh-CN/docs/…
blog.cssforest.org/2011/05/19/…
關注
感謝大家關注我的公眾號,一起學習成長~