iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0
Modern Web

前端迷走中:從零開始的新手之路系列 第 25

[Day 25] 選擇不障礙,讓 CSS 幫你──Cascading 決定最終宣告值

  • 分享至 

  • xImage
  •  

昨天我們提到選擇器之間的優先順序由具體度(Specificity)決定。

不過,規則的優先順序不只會受到選擇器的具體度影響。

在比較選擇器的具體度之前,還需要先比較規則的來源與重要性等因素。

只有在無法由這些因素分出優先順序時,才會往下比較選擇器的具體度。

這整套比較優先順序的流程稱作Cascading。

透過這套流程,CSS可以由多種來源的樣式表,決定出網頁最終的樣式。所以這樣的樣式表語言才會叫做CSS(Cascading Style Sheets)。

Cascading

如果同時有多個符合條件的規則,對某個元素的某個屬性宣告了不同值而彼此衝突時,就需要透過Cascading這套流程判斷這些宣告值的優先順序,以決定最終要套用的樣式。

Cascading的七個步驟

CSS Cascading and Inheritance Module Level 6將Cascading的流程依優先順序分成七個步驟:[1]

  • 1.來源與重要性 Origin and Importance
  • 2.Context
  • 3.行内樣式 The Style Attribute
  • 4.分層 Layers
  • 5.具體度 Specificity
  • 6.作用域鄰近度 Scope Proximity
  • 7.出現順序 Order of Appearance

今天先討論前兩個步驟。

來源與重要性Origin and Importance

樣式表的來源

在比較宣告值的優先順序時,首先要先看這些宣告來自哪種樣式表。

CSS將宣告依樣式表的來源分成三種,優先順序由高至低分別是:

  • 作者宣告(author declarations)
    來自作者樣式表
  • 使用者宣告(user declarations)
    來自使用者樣式表
  • 使用者代理宣告(user agent declarations)
    來自使用者代理樣式表

作者樣式表

作者樣式表,是網頁開發者在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]

  • 轉場宣告 Transition declarations
  • 重要的使用者代理宣告 Important user agent declarations
  • 重要的使用者宣告 Important user declarations
  • 重要的作者宣告 Important author declarations
  • 動畫宣告 Animation declarations
  • 普通的作者宣告 Normal author declarations
  • 普通的使用者宣告 Normal user declarations
  • 普通的使用者代理宣告 Normal user agent declarations

如果衝突的宣告,重要性一樣,也來自同一種樣式表,接著就會進入下一個步驟Context。

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


上一篇
[Day 24] 選擇不障礙,讓CSS幫你──Specificity決定選擇器優先順序
系列文
前端迷走中:從零開始的新手之路25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言