咦, !important 怎麼沒用?- 來了解 Cascading Sorting Order

Amdis Liu
Frochu
Published in
7 min readFeb 6, 2022
Photo by KOBU Agency on Unsplash

我原本只意識到這是要拿來強制覆寫 external libraries 樣式的極端手法,在 MDN 中也有提到這是 anti-pattern,MDN 中對 !important的使用建議是 :

- 優先考慮使用一般 CSS specificity (選擇器優先級) 方法覆寫 style
- 只在單頁內覆寫外部 CSS 時使用
- 不要在寫 plugin 時使用
- 不要在全站的 global CSS 使用

近日看了 Google 工程師 Una Kravets 的一部 Youtube 影片 How does !important actually work? (It’s not what you think!) 後才發現,來自不同 CSS origin 的 style precedence 在加上 !important 後, 其 precedence 跟原本的 normal style 相比是被反轉的 transition 和 animation CSS 被定義成另兩種特殊 origin 一起來搶位置其中 transition 的優先權還最高

下面將來看 W3C spec 中如何定義:
1. Cascading Origins — CSS 來源
2. Cascading Sorting Order — 來自不同 origin 的 style 優先順序

Cascading Origins — CSS 來源

Spec section 6.2定義了 3 種 core origins 和兩種從 CSS 擴充出來的 origin :

以較白話的方式來說:
1. Author Origin : 來自網站本身的樣式
2. User Origin : 來自使用者的樣式。
在網路上搜尋了一下,Chrome 自身在 Chrome 33 中移除支援使用者樣式 (https://codereview.chromium.org/66383005/),Firefox 應該還有辦法使用自定義 (see : https://www.thoughtco.com/user-style-sheet-3469931)
3. User-Agent Origin : 來自瀏覽器的樣式
4. Animation Origin — CSS animation properties 執行時所產生用來表達 animation effect 的 virtual rules
5. Transition Origin — CSS transition properties 執行時所產生用來表達 transition effect 的 virtual rules

註:在 W3Schools 中, css rule 的定義為

A CSS rule consists of a selector and a declaration block.

圖片擷取自 W3Schools

Cascading Sorting Order — 來自不同 origin 的 style 優先順序

看以下這段 css rules ,最後 text-indent , font-style, font-size 的值分別是什麼?

取自 w3c spec 6.3 EXAMPLE 20

答案是 ……

取自 w3c spec 6.3 EXAMPLE 20

原因可從 spec section 6.1 的定義看出:

Origin precedence from w3c spec

normal user agent style 的宣告是最低權重完全可以預期,覆寫瀏覽器樣式是開發者日常,但可以看到 2 ~ 4 和 6 ~ 8 的順序是相反的而且 CSS transition 有著最高優先權,CSS Animation > Normal Styles,所以 text-indent 和 font-style 是取 user stylesheet 定義的值,因為 user-style + !important > author-style + !important

而這個權重反轉的遠因可以從 !important 的定義段落裡看到 ,為了要平衡原有權重有差異,在使用 !important後,讓 precedence 反轉,讓 user & user-agent style 有機會藉此提升自身的 precedence order:

important annotation 宣告,取自 w3c spec

後記

在 Chrome 99, Firefox 97, Safari 15.4 中加入了一個新的屬性 “@layer” ,在 spec section 6.4 的說法是,提供一個在 single origin 中可以結構化組織自定義 css rule precedence 的方法。

有興趣的人可以看 Una Kravets 另一部 YT 影片Chrome Developer 文章 ,在 Una Kravets 影片的留言也有人問到一個重要的問題:CSS nesting 的 library 如 SCSS 是否會加進 cascade layer 功能,作者的回答是

There is open discussion at the CSSWG. One consideration is how to make sure it doesn’t break existing nesting for something as popular as Sass

加入 layer 功能後,cascade precedence 鏈變成這樣呢~:

取自 Google Developer (https://developer.chrome.com/blog/cascade-layers/)

參考資料

How does !important actually work? (It’s not what you think!) — by Una Kravets

CSS Cascade Layers: An overview of the new @layer and layer() CSS primitives — by Una Kravets

--

--

Amdis Liu
Frochu
Editor for

Web frontend / mobile developer. Editor of publication Frochu: https://medium.com/frochu .