計算 CSS Selector 的權重


Posted by GL on 2022-03-06

1912 年, RMS Titanic 是當時世界上最大的船隻,號稱「不會沈沒的郵輪」,從英國的南安普敦出發,計畫前往美國紐約市,但這艘郵輪最後沒有如願抵達,因為它在航程中撞上了冰山,超過 2200 位乘客和船組人員中,只有 712 名獲救。多年後,以這艘郵輪作為題材發想的電影"鐵達尼號"風靡全球,也成為李奧納多皮卡丘(? 的代表作。劇中令人動容其中一幕就是當郵輪快要沉沒時,乘客們紛紛爭先恐後地湧入甲板,想要坐上為數不多的救生小船。

然而,船上的大多男性還是決定讓老弱婦孺先上小船。是紳士精神還是人道主義讓這些人做出如此權衡?

另一方面,剛熱戀,結果發現男友小明是超級媽寶的你,選在一個夜深人靜剛喝了小酒的微醺夜,試探性地問小明一個亙古不變的經典問題,如果我跟你媽同時掉到海裡你會先救誰?

當遇到要選擇優先順序的時候,什麼(or 誰) 比較重要,哪個優先? 人們常常傾向依據一些條件作為衡量的判斷基礎。

在 CSS 的世界裡,若許多 CSS 同時作用在同一個元素時,瀏覽器要被設計成遵守哪一個呢? 是先出現的?還是後出現的? 是命名比較長的? 還是數值比較大的?

為了統一衡量的標準,定義了 "Specificity", 中文稱為 "權重",CSS 的權重表示一個 css 選擇器(selector) 和其元素的相關程度。相關性越強,表示其權重越高。

什麼意思呢?有點像是警匪電影中警探在找尋嫌疑犯,當目擊者描述的越精確,採取目擊者說法就會越優先,假使

甲目擊者說是嫌疑犯約 170公分
乙目擊者說嫌疑犯是一位約 170公分,穿著紅白條紋上衣的人
丙目擊者說嫌疑犯是約 170公分,穿著紅白相間條紋上衣,藍色牛仔褲,頭戴紅白相間條紋毛帽,圓形黑框眼鏡的人

如果你是警探,當然會先以丙目擊者的描述優先尋找。

可以把權重當作是優先級的概念,權重高低決定了同一元素的情況下的哪些 CSS 屬性優先套用,讓你在寫 CSS 時瞭解最後被選擇顯示的是哪個。

所以,CSS 權重是如何比較的呢?

規則一: 網頁載入 CSS 的順序

行內 (inline) CSS > HTML 內部載入 CSS > 外部載入 CSS

  1. inline style
    <h1 style="color: #fff000;">H1 標題</h1>

  2. HTML 文件的<head>標籤中,元素在 <style> 撰寫 CSS
    寫在 <style> 標籤

    <head>
    <style>
     h1 { color: #000000; }
    </style>
    </head>
    
  3. CSS 程式碼統一寫在另一個檔案 (.css),再到 HTML 的 <head> 中引入
    <head>
     <link href="外部css檔案的路徑" rel="stylesheet">
    </head>
    

規則二: CSS 的撰寫順序

由於CSS 的讀取是由上而下的,權重相等時,後寫的會覆蓋過先寫的樣式

// h1 會顯示 #ffffff,因為後者會蓋過前者

h1 { 
  color: #000000; 
}

h1 { 
  color: #ffffff; 
}

規則三: CSS 的權重記分

若權重不同時,權重值高的優先

根據 MDN 文件,權重是由選擇器中不同的選擇器類型的數目決定

選擇器類型分成四種,想像有四個區塊的數字:0-0-0-0,優先級別從左而右為

  1. inline style
  2. id
  3. class / psuedo-class / attribute
  4. element / psuedo-element


圖片來源

當兩個選擇到同一元素,就從最左邊的區塊開始比兩者權重的數字,如果相同,就往下一級比;如果不同的話,數字多的權重較大。如果兩組的權重數字完全相同的,就是樣式擺放的先後順序了,

實際上不同區塊的數字,代表的只是所在區塊的選擇器類型數目,所以不能進位到其他區塊,而且這樣也很奇怪,你有 99 個 class 並不表示就可以換 1 個 id。

一、*:全站預設值,為 0-0-0-0

//全站預設值

*{
    padding: 0
    margin: 0
 }

二、 Element:為 0-0-0-1

div, p, ul, ol, li, header, footer....

三、 class / psuedo-class / attribute:三者皆為 0-0-1-0

// HTML

<h1 class="myclass">Hello World!</h1>


// CSS

.myclass {
  color: blue;
}

四、id:為 0-1-0-0

// HTML

<h1 id="myid">Hello World!</h1>

// CSS

#myid {
  color: red
}

五、inline style : 為 1-0-0-0

<div style="color:green">
    I am priority
</div>

六、!important: 為 1-0-0-0-0

!important 應該算是西洋棋裡的王后,大老二的黑桃二,可蓋過所有的權重,
它的用法是寫在 CSS 屬性後方,例如:

div{
  padding:10px !important;
}

要蓋過!important,辦法有

  1. 寫在它後面並也加上!important
.box{
    background-color: #f00;!important
}

.box{
    background-color: #aaa;!important
}
  1. 加上比數量更多的!important
// background-clor 會顯示 #f00,因為有兩個 !important

.box{
    background-color: #f00;!important !important
}

.box{
    background-color: #aaa;!important
}

好比要贏過一萬分的玩家,就是把自己變成兩萬分、三萬分...,但這樣互拼的結果,最後會造成 CSS 中一大堆 !important,這樣沒有彈性也不好維護與管理,建議多用 class 來寫 CSS,必要時才能有效利用權重的特性來覆蓋元素,非到不得已不輕易使用 !important,它可以視為最後的王牌,相信你也不會在當別人出梅花 3 的時候,就把黑桃 2 丟出去。

Quiz

1. body div ul li a span 總共 6 個 element  => 加起來是 0-0-0-6

2. li #myid 一個 element 加上一個 id => 0-1-0-1

3. h3.myclass ~ li 兩個 element 加上一個 class => 0-0-1-2

4. form input[type=name] 兩個 element 、一個 attribute => 0-0-1-2

小結:

!important > inline style > ID > Class/psuedo-class(偽類)/attribute(屬性選擇器) > Element > *

參考來源:


#css #CSS 權重







Related Posts

1/26 開發日記

1/26 開發日記

從 React 原始碼看 keyPress 與 keyDown 事件

從 React 原始碼看 keyPress 與 keyDown 事件

Print a list from n times 1 to n times 9

Print a list from n times 1 to n times 9


Comments