昨天我們提到選擇器之間的優先順序由具體度(Specificity)決定。
不過,規則的優先順序不只會受到選擇器的具體度影響。
在比較選擇器的具體度之前,還需要先比較規則的來源與重要性等因素。
只有在無法由這些因素分出優先順序時,才會往下比較選擇器的具體度。
這整套比較優先順序的流程稱作Cascading。
透過這套流程,CSS可以由多種來源的樣式表,決定出網頁最終的樣式。所以這樣的樣式表語言才會叫做CSS(Cascading Style Sheets)。
如果同時有多個符合條件的規則,對某個元素的某個屬性宣告了不同值而彼此衝突時,就需要透過Cascading這套流程判斷這些宣告值的優先順序,以決定最終要套用的樣式。
CSS Cascading and Inheritance Module Level 6將Cascading的流程依優先順序分成七個步驟:[1]
今天先討論前兩個步驟。
在比較宣告值的優先順序時,首先要先看這些宣告來自哪種樣式表。
CSS將宣告依樣式表的來源分成三種,優先順序由高至低分別是:
作者樣式表,是網頁開發者在HTML檔案中使用的樣式表。
網頁開發者可以透過三種方式設定HTML的樣式。
一種是外部樣式表。不論是在HTML的<head>
中使用<link>
元素連結,或是在<style>
中使用CSS的@import
匯入外部的CSS檔案;
另一種是內部樣式表。直接將CSS程式碼寫在HTML的<style>
元素裡;
還有一種是行内樣式。直接對元素添加style
屬性,以CSS程式碼設定樣式。
使用者樣式表,是用戶使用瀏覽器時,以其他CSS檔案或是透過擴充功能,另外套用的樣式表。
不過現在比較少這麼做。如果瀏覽器是用Chrome,只能透過擴充功能來達成;Firefox雖然可以直接使用其他CSS檔案,但需要先打開瀏覽器的隱藏設定。[2]
使用者代理樣式表,是瀏覽器等使用者代理程式(user agent)預設的樣式表。所以即使沒有設定樣式,每種HTML元素仍然有各自預設的樣式。
由於每一家瀏覽器提供的樣式表不同,同一個HTML用不同瀏覽器開啟時可能會以不同的預設樣式呈現。這些樣式表,可能是用實際的樣式表,也可能是用其他程式碼來模擬。[3]
!important
反轉優先順序一般來講,這三種來源的樣式表,優先順序是作者樣式表>使用者樣式表>使用者代理樣式表。
不過如果在宣告樣式時加上!important
,就會反轉這個順序,變成使用者代理樣式表>使用者樣式表>作者樣式表。
!important
需要放在宣告後面並以空格相隔,如果屬性有多個值就要放在最後的結尾。可以參考以下由MDN提供的例子:
p[style*="purple"] {
color: rebeccapurple !important;
}
雖然加了!important
,可以迅速提高宣告的優先順序,但通常不會這麼做,因為後續宣告的其他樣式也需要加上!important
才會生效。
需要提高宣告的優先順序,一般會建議透過分層(Cascade Layer)或增加選擇器的具體度來處理;
如果不得不這麼做的時候,也應該在註解說明這麼做的理由。[4]
除了來源跟重要性,從CSS Cascading and Inheritance Level 3開始,規範在這個步驟還會考慮宣告的屬性是否為動畫Animation或Transition(這裡先譯作轉場)類型。
動畫類型的宣告,優先順序會高於作者樣式表的普通宣告,低於作者樣式表加上!important
的重要宣告;
轉場類型的宣告則會高於所有加上!important
的重要宣告,不論這些宣告來自哪一種樣式表。
至於Animation跟Transition是什麼,之後有機會再提,這裡就先帶過~
所以宣告的優先順序,由高至低完整列出會是:[01]
如果衝突的宣告,重要性一樣,也來自同一種樣式表,接著就會進入下一個步驟Context。
CSS Cascading and Inheritance Level 4開始,Cascading的流程中多了Context的步驟,用於處理來自encapsulation context的宣告。
文件使用的標記語言,可以同時提供來自不同encapsulation context的宣告。DOM裡,shadow tree的tree context就是encapsulation context的一種。
當衝突的宣告來自不同的encapsulation contexts時,就會比較這些宣告的context。
一般的情況下,會是context比較外層的宣告優先;
但如果宣告加了!important
,則會是context比較內層的宣告優先。
When comparing two declarations that are sourced from different encapsulation contexts, then for normal rules the declaration from the outer context wins, and for important rules the declaration from the inner context wins.
由於這個步驟涉及的技術比較難,這裡就先帶過~
今天我們提到CSS是以Cascading的流程,決定衝突的宣告值之間的優先順序。
昨天提到比較選擇器的Specificity,只是這個流程的其中一環。
包括Specificity在內,目前規範將Cascading的過程分成7個步驟。
在第一個步驟中,會先判斷宣告來自哪種樣式表,以及宣告是否加上!important
。
如果是一般情況,優先順序是作者樣式表>使用者樣式表>使用者代理樣式表;但如果加上!important
,則優先順序會反轉。
如果在第一個步驟分不出優先順序,且宣告來自encapsulation context,就會進入第二個步驟,比較這些宣告的context。
如果第二個步驟也分不出,就會進入第三個步驟。
不過時間不多了,讓我們下集待續~
[1]: W3C, CSS Cascading and Inheritance Module Level 6
[2]: ThoughtCo., What Is a User Style Sheet?
[3]: MDN, Introduction to the CSS cascade
[4]: MDN, Specificity