
CSS
剛開始學習容易上手
往後卻難以維護
CSS 較鬆散, 非常仰賴攥寫的順序
但這些都比不上不懂 Specificity 的恐怖!XDDD
Specificity 看不懂?
Specificity 譯為優先級、特定度、權重
註:O’reily 翻譯為特定度;MDN 翻譯為優先級;有些翻譯為權重。本文一律以「權重」表示 Specificity。
Specificity 幹嘛的?
決定你的元素優先吃哪一個樣式的其中一個因素!
Chris 這篇文章解釋得很清楚:Cascade 動作是由 Specificity 和 Ruleset order 作用,決定要套用的 CSS。
換句話說
先比權重,再比順序!
- 當兩個 CSS 宣告同時作用在一個元素時:
- 權重高
- 優先生效!
- 相同權重時
- 後寫的 CSS 會覆蓋先寫的 CSS
- 權重高
透過範例了解一下剛剛在說什麼
我們有一個區塊元素 div 包覆著一個 button 。
這個 button 的 class 有 button(基本按鈕的樣式)、button__disabled(無法點擊的狀態樣式)。
HTML
<div>
<button class="button__disabled button">Click me</button>
</div>
CSS
.button {
padding: 10px 20px;
font-size: 32px;
border-radius: 3px;
border: none;
/* notice below 被 button__disabled 的樣式覆蓋了 */
background: #eee;
color: #333;
cursor: pointer;
}
.button__disabled {
background: #ccc;
color: #999;
cursor: not-allowed;
}
透過範例可以了解兩件事:
- 決定要套用樣式的基礎並不在於我們在 HTML Element 上引用 Class 的順序,而是,該 class 在我們攥寫 CSS 樣式表當中的順序。
- 若在同樣都只有一個 class 選擇器的狀況下(.button、.button__disabled)
- 後面寫的樣式宣告(
.button__disabled) - 在 CSS 樣式表中,較前面的內容有指定同一個 HTML Element 的選取器(
.button) - 並且攥寫了重複的內容時(
background、color、cursor) - 後面寫的樣式宣告(
.button__disabled)會優先被套用,覆蓋掉原本的樣式(.button)
- 後面寫的樣式宣告(
權重計算的基本規則

如上圖,檢查對應的出現的次數、由左向右比較,看 W3C 的定義,其實是從 id=> class => element,檢查完再去看是否有設定 important 行內樣式。但我把它們集合起來畫成一張對應的表,比較方便理解、查閱跟記憶。
我的 CSS Specificity 的 CheatSheet:
| specificity | 條件 |
|---|---|
| 1-0-0-0-0 | !important |
| 0-1-0-0-0 | HTML Element 中的行內樣式, style="" |
| 0-0-1-0-0 | #id |
| 0-0-0-1-0 | .class, :pseudo class, attribute |
| 0-0-0-0-1 | element (h1), ::pseudo element |
| 0-0-0-0-0 | *, +, >, ~, 空格, :not() |
例外 :not |
:not 雖是偽類,可是其無任何權重,但 :not(.class) 依據參數還是會增加權重 |
有趣的小工具:CSS權重計算機
實例
一個新手容易踩的雷:使用 id 選取器,等專案越做越大時,開始有製作新的 table 需求時…
#content table { }
/**
* 不,我寫的東西無法生效 :(
*/
.my-new-table { }
- 命名沒表現任何語意,看不來是何種 table
- 使用
id選取器則侷限了這個 table,只能套用在這個名為 content 的id中
通常會有兩種做法
- 重構,移除
id - 為了生效,算了不管它了!我要以較高的權重覆蓋它!
- 因為若專案較大時,有時無法確定移除
id對整個專案的影響
- 因為若專案較大時,有時無法確定移除
使出我的覆蓋技能
#content table { }
#content .my-new-table { /* 耶,可以看到我的樣式了! */ }
結束這回合…了嗎?
開始進入惡性循環,權重只要一開始疊的高,以後只能越設越高!
!important 該死?
“Rules are the children of principles.” - Jamie Mason
When to use !important properly?
有些開發者都覺得 !important 是萬惡的,若 !important 真的如此該死,當初又何必設計它的存在呢?
其實只要:
了解使用目的!
確保你的樣式在 global 都要能 work
而不是為了覆蓋(fix)你改不掉的樣式
Keep It Low at All Times
永遠保持最低的權重,這就是原則!
How to keep it low?
-
絕對不要使用
IDID辦得到的事,Class全部都可以ID不能重複使用就算了,還會增加權重- 若真無他法一定要使用的話:
- hack:
[id="your-id"](attribute 0-0-1-0) (等同於 class 的權重及選取,但可讀性就較低了,不建議不建議不建議!)
-
選取器不要巢過了頭
- 建議不要超過三層
-
不要限定你的選擇器
.nav {}可以做到的事,不要用ul.nav {}
-
盡可能地使用
class- 並且保持低權重,讓大家都有相同的權重,公平!
YA!CSS 又 變瘦 變輕了!(是權重不是檔案大小,囧)
理解完,考自己一下,你應該會笑:)
Reference
- Spec
- Book
- CSS 重構 - Steve Lindstrom 著、陳健文 譯(好想工作室有這本書)
- Internet
- Day20:小事之 CSS 權重 (css specificity) - iT邦幫忙
- cssspecificity.com
- CSS guildlines
- [Hacks for dealing with specificity - CSS Wizardry](
留言