
CSS At 規則
CSS 的語法中有一個特殊的存在——At 規則,這個規則就喜歡和別人長得不一樣,所以拉出來單獨一篇介紹一下。

Canis
2024-03-29
約 10 分鐘
本來打算直接開始講 CSS 屬性的,但是我覺得既然前面已經提到了優先級這個東西,那就先來說一下好了。不過特異性的計算其實只是在確定具體樣式的其中一步,所以我這篇文不會只有講特異性。
特異性(Specificity)就是所謂的優先級。這個是瀏覽器用來確定 CSS 與元素相關度(權重)的演算法,並且決定具體要應用在元素上的屬性值。
這個演算法用來計算 CSS 聲明(CSS Declaration)的權重(Weight),而權重是由「與元素匹配的選擇器(含偽元素)」中每個權重類別的選擇器的數量決定。如果有超過一個聲明匹配同一個元素,在經過計算之後會套用權重最大的聲明。
下面會說到各種選擇器,不知道這些選擇器在幹嘛的可以看一下認識 CSS 這篇文。
ID:
只有「ID 選擇器」。
Class
包含「類選擇器」、「屬性選擇器」、「偽類」。
Type
包含「類型選擇器」、「偽元素」。
在計算權重時,有一些特殊的情況:
:where()」偽類(包含它的參數)不會在計算範圍內。雖然不在計算範圍裡面,但是還是會起作用。&)1、「:is()」偽類,它們不會讓權重的值有什麼變化,因為它們的作用只是讓程式更加簡潔。!important 這兩個是例外中的例外。前者會覆蓋內部和外部樣式的任何聲明,所以優先級最高。而 !important 則是不管優先級的結果怎麼樣,它偏愛謀權篡位,它會直接破壞並應用,所以盡量不要使用。在特殊情況的第 4 點有說到內嵌樣式的優先級最高(不說 !important 的話),所以權重類型其實應該是四個,下面我會用四個權重來做講解。
在開始計算前要明白,之所以要計算特異性,是為了解決樣式(聲明)的「衝突」。

上面有說到,權重會分成四個類別:內嵌樣式、ID、Class、Type(元素標籤或偽元素),它會組成這樣的格式:(內嵌樣式, ID, Class, Type),這樣可以方便判斷要使用什麼聲明。
我們使用下面的例子來看一下:
HTML:
<h1 class="title">Title</h1>使用者代理程式樣式2(Chrome 預設樣式):
h1 {
display: block;
font-size: 2em;
margin-block-start: 0.67em;
margin-block-end: 0.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
font-weight: bold;
unicode-bidi: isolate;
}自訂樣式:
.title {
color: red;
font-size: 40px;
}
h1 {
font-size: 26px;
}
div h1.title {
font-size: 3em;
font-size: 30px;
}根據觀察,衝突的樣式是 font-size。
重要性從高到低,依次是:
!important 的自訂樣式!important 的使用者代理程式樣式所以至此,可以淘汰使用者代理程式樣式的 font-size。
就是上面提到的「選擇器權重類型」,這邊再簡單統整一下:
格式:(內嵌樣式, ID, Class, Type)
| 項目 | 說明 |
|---|---|
| 內嵌樣式 | 有就是 1,沒有就是 0。 |
ID | ID 選擇器數量。 |
Class | 類選擇器、屬性選擇器、偽類數量。 |
Type | 類型選擇器、偽元素數量。 |
因為使用者代理程式樣式已經淘汰,所以不考慮了。這是結果:
| 項次 | 項目 | 結果 |
|---|---|---|
| 1 | .title | (0, 0, 1, 0) |
| 2 | h1 | (0, 0, 0, 1) |
| 3 | div h1.title | (0, 0, 1, 2) |
到此已經算出來了,那麼具體比較的方式就是由左至右比較,誰大就用誰。
三個都為 0,所以下一步。
三個都為 0,所以下一步。
項次 1 = 項次 3 > 項次 2,所以項次 2 淘汰,然後進到下一步。
項次 3 > 項次 1,所以項次 1 淘汰,所以最後 font-size 的值應該為 3em 或 30px。
因為無法確認究竟是 3em 還是 30px,所以會進入下一步。
較後面的會覆蓋前面的,所以結果 font-size 的值應該為 30px。
繼承其實就是字面上的意思。那有些屬性可以被繼承,有些不行,通常和文字有關的(如字體大小、行高)可以被繼承,像是寬高、位置等就不能被繼承。具體可不可以最好是看官方的說明,例如說 width 這個屬性,它是不能被繼承的,它會在 width - CSS: Cascading Style Sheets | MDN Formal definition 部分的 Inherited 欄位註記。

繼承需要滿足兩個條件:
當兩個條件都滿足,那麼就會繼承父元素或是更上層的元素的值。如果都沒有,就繼承使用者代理程式樣式的值,例如 width 的使用者代理程式樣式值是 auto。如此一來,就可以確保每一個屬性都有值了。
樣式計算大概就這樣了,有想到要補充的會再更新或寫一篇新的。推薦一個計算器——Specificity Calculator,可以讓你更好地了解特異性。
我在 HTML 結構與元素這篇文有提到區塊級元素或行內元素,但是其實說法不太準確,因為官方有說過不再使用這種說法。那麼我為什麼還這樣解釋呢?不是因為我不聽勸喔,是因爲瀏覽器有所謂的使用者代理程式樣式。這個東西是用來定義預設樣式的,比如說 div 之所以是區塊級元素,是因爲它的預設樣式有 display: block;,所以它才是區塊級元素。 ↩
一個能設計 UI/UX 的前端工程師。平時有想法的時候,會坐到電腦前開始把想法慢慢地實現出來。白話文就是「喜歡沒事找事來折磨自己」。