當我們在討論CSS選擇器優先順序的時候,我們再討論什麼?
其實很多人都對此有點模糊,那我換個方式問: 一個CSS屬性的最終值是怎麼來?
回答 : CSS屬性的最終值是通過層疊計算得來的。
那什麼是層疊計算呢?
我通俗的理解,其實就是先計算再重疊。
層疊是CSS的一個基本特徵,它是一個定義瞭如何合併來自多個源的屬性值的演算法。它在CSS處於核心地位,CSS的全稱層疊樣式表正是強調了這一點。
計算過程
計算的過程指的是使用者代理(瀏覽器只是使用者代理的一種“例項”)在渲染HTML的時候,對CSS進行層疊計算的過程(這裡不討論瀏覽器的渲染、重繪等觸發時機)。
為了方便理解,這裡只針對一個屬性值(padding
)進行討論,其他的屬性值都是一樣的過程。
demo:
<div class="taobao_com" id="taobao_com" data-show="true">
<div class="taobao"></div>
<p>taobao.com</p>
</div>
複製程式碼
div{
padding:1px;
}
.taobao_com{
padding:12px;
}
div .taobao{
padding:123px;
}
.taobao_com .taobao{
padding:1234px;
}
複製程式碼
在屬性的計算之前,會對每個文件元素的每個屬性上的值進行排序 (W3C文件地址):
1. Transition declarations [CSS3-TRANSITIONS]
2. Important user agent declarations
3. Important user declarations
4. Important override declarations [DOM-LEVEL-2-STYLE]
5. Important author declarations
6. Animation declarations [CSS3-ANIMATIONS]
7. Normal override declarations [DOM-LEVEL-2-STYLE]
8. Normal author declarations
9. Normal user declarations
10.Normal user agent declarations
複製程式碼
排序靠前的會比靠後的優先順序要高。 1 > 2 > 3 > 4 > 5 ...
假設我們的使用者代理是Chrome瀏覽器,那麼當我們要計算A:<div class="taobao"></div>
的padding
值的時候,會有這麼一個排序過程(簡化):
1. 瀏覽器中對該標籤的``padding``預設值
2. 開發者對該標籤的 ``padding`` 進行宣告的值
3. 瀏覽器中對該標籤的 ``padding`` 進行 **!important** 宣告的值
4. 開發者對該標籤的 ``padding`` 進行 **!important** 宣告的值
複製程式碼
那麼在demo裡面,分別寫了4條padding
的的宣告,但都會被排在層疊順序的開發者對該標籤的 padding
進行宣告的值之中,而且padding
沒有更高權重的宣告瞭,那麼就會對這個宣告佇列裡的宣告進行優先順序的計算。
所以,!important 跟選擇器優先順序是什麼關係?
優先順序的計算
優先順序的計算首先是 選擇器權重 的優先順序計算,然後是 宣告先後順序 的優先順序計算。
選擇器優先順序的權重計算
這時候,才到了選擇器優先順序登場。
選擇器的權重並不是網上很多人說的
選擇器通過權重值 1(div等)、10(class)、100(id)
這樣的方式進行的,這只是別人理解出來的東西,真正的計算原理可以翻閱W3C文件選擇器權重的計算。
文件指出:
A selector’s specificity is calculated for a given element as follows:
1.count the number of ID selectors in the selector (= A) 2.count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= B) 3.count the number of type selectors and pseudo-elements in the selector (= C) 4.ignore the universal selector
文件也給了例子:
Examples:
* /* a=0 b=0 c=0 */
LI /* a=0 b=0 c=1 */
UL LI /* a=0 b=0 c=2 */
UL OL+LI /* a=0 b=0 c=3 */
H1 + *[REL=up] /* a=0 b=1 c=1 */
UL OL LI.red /* a=0 b=1 c=3 */
LI.red.level /* a=0 b=2 c=1 */
#x34y /* a=1 b=0 c=0 */
#s12:not(FOO) /* a=1 b=0 c=1 */
.foo :matches(.bar, #baz)
/* Either a=1 b=1 c=0
or a=0 b=2 c=0, depending
on the element being matched. */
複製程式碼
大致意思就是,把權重分為了 A,B,C 三個級別,A > B > C , A,B,C 直接各自計算。也就是會優先計算 A 的權重,如果相等會計算 B 的權重,以此類推。
所以才有了100、10、1的說法,但很不準確。
結合之前的demo,我們來計算下權重值:
1:
div { /*type selectors*/
padding:1px; /*a = 0 , b = 0 , c = 1*/
}
複製程式碼
2:
.taobao_com{ /*class selectors*/
padding:12px; /*a = 0 , b = 1 , c = 0*/
}
複製程式碼
3:
div .taobao{ /*type selectors + class selectors*/
padding:123px; /*a = 0 , b = 1 , c = 1*/
}
複製程式碼
4:
.taobao_com .taobao{ /* class selectors + class selectors */
padding:1234px; /*a = 0 , b = 2 , c = 0*/
}
複製程式碼
由於A位相等,B位差異的最大值在 4 ,得到的結果將會是 第4條宣告 勝出: 1. a = 0 , b = 0 , c = 1 2. a = 0 , b = 1 , c = 0 3. a = 0 , b = 1 , c = 1 4. a = 0 , b = 2 , c = 0
宣告先後順序
當 A 、B 、C 所計算的權重都相等時(ABC三個值相等)相等時,後面宣告的值將會是最終的計算值。
最終得到了CSS屬性的值。