「CSS Specificity」相關筆記

重點整理

Specificity

Specificity(以降以「權重」稱之)的高低影響哪一些 CSS 樣式會發生作用。 設定好的 CSS 沒有作用,可能就是 CSS 樣式的權重沒有妥善安排,導致編寫好的 CSS 樣式沒有如預期般套用到 HTML 元素上。

權重從低至高順位分組如下:

  1. universal selector 與 inherited style:使用*選取「全部」與繼承得來的樣式,兩者的權重皆為0-0-0-0-0;最低的權重

  2. element selector、::pseudo-element selector:選取 HTML 元素或偽元素,權重為0-0-0-0-1

    • HTML 元素:html、body、section、div、p……等 HTML 元素(element)
    • 偽元素:

      A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s).

    參考MDN,偽元素指的是 HTML 元素的「某一個部份」,較常見的大概是::after、::before與::first-letter

  3. .class selector、:pseudo-class selector、[attribute] selector:選取 class、偽類或具有特定屬性(attribute)的 HTML 元素,權重為0-0-0-1-0

    • 偽類:

      A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s).

    參考MDN,偽類指的是 HTML 元素的「某一種狀態」,最常見的大概是:hover

    • 屬性:參考MDN,以input[type="checkbox"]為例,就是「選取所有是 checkbox 特性的 input 元素」
  4. #id selector:選取擁有某 id 的 HTML 元素,權重是0-0-1-0-0

  5. inline style(比如<p style="color: red;">text</p>):權重是0-1-0-0-0,不過這樣會讓原始碼的維護性變差,所以還是避免使用吧

  6. !important:擁有最大的權重1-0-0-0-0,而後發的!important會壓過先寫出來的!important

權重的計算方式

參考以上劃分的六種權重分組,將選取器中屬於同一組的選擇器條件相加後進行比大小。 舉個 🌰,假設以下兩種color的樣式設定位在同一份原始碼裡面:

#blue {
  /* 第一組樣式 */
  color: blue;
}

div p {
  /* 第二組樣式 */
  color: red;
}

而 HTML 內容如下:

<div>
  <p id="blue">
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consectetur,
    magnam!
  </p>
</div>

第一組樣式的選取器為#id 一個,權重為:0-0-1-0-0 第二組樣式的選取器為 HTML 元素兩個,權重為:0-0-0-0-2 第一組樣式的權重大於第二組,故以上的<p>會是藍色:

See the Pen css specificity by Charlie (@Charlie7779) on CodePen.

需注意的是,CSS 的權重並不是十進位制,選取五十個.class 做出來的 CSS 樣式也比不過選取一個#id 宣告出來的樣式。 舉個 🌰,假設以下兩種background-color的樣式設定位在同一份原始碼裡面:

#yellow {
  background-color: yellow;
}

.c1 .c2 .c3 .c4 .c5 .c6 .c7 .c8 .c9 .c10 .c11 {
  background-color: green;
}

而 HTML 內容如下:

<div class="c1">
  <div class="c2">
    <div class="c3">
      <div class="c4">
        <div class="c5">
          <div class="c6">
            <div class="c7">
              <div class="c8">
                <div class="c9">
                  <div class="c10">
                    <div class="c11" id="yellow"></div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

那麼該<div>的背景顏色會是黃色:

See the Pen css specificity by Charlie (@Charlie7779) on CodePen.

在 CSS Specificity 的宇宙裡,團結起來的五十個.筷子還是會被#●門夾爆的。

快速判別樣式的權重

在CSS Specificity的宇宙裡,就算你爸變兔子.class也打不過#id

權重相等時,後發覆蓋先寫的樣式

假設style.css的內容如下:

p {
  color: blue;
}

而 HTML 內容如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="./style.css" />
    <style>
      p {
        color: green;
      }
    </style>
  </head>

  <body>
    <p>
      Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consectetur,
      magnam!
    </p>
  </body>
</html>

因為<style>比<link rel="stylesheet" href="./style.css">晚執行,所以<p>會是綠色(按下▶執行程式碼看結果):

而如果調換<style>與<link rel="stylesheet" href="./style.css">的順序:

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      p {
        color: green;
      }
    </style>
    <link rel="stylesheet" href="./style.css" />
  </head>

  <body>
    <p>
      Lorem ipsum dolor, sit amet consectetur adipisicing elit. Consectetur,
      magnam!
    </p>
  </body>
</html>

<p>就會是藍色(按下▶執行程式碼看結果):

LVHA

問:為什麼超連結的 CSS 樣式最好以「link-visited-hover-active」的順序從上到下書寫? 答:因為樣式權重相等的時候,後發的樣式會覆蓋先寫的內容。 假設使用「link-hover-active-visited」的順序來設定 CSS 樣式:

a:link {
  color: blue;
}
a:hover {
  color: aqua;
}
a:active {
  color: red;
}
a:visited {
  color: purple;
}

那一個被點擊過的(:visited)超連結,即使在:hover或:active的狀態,也不會被套上:hover或:active的樣式,因為:hover與:active通通被:visited的樣式蓋過去了。 點擊過以下範例的超連結後,即使把游標停留在連結上,文字也不會變為水藍色:

See the Pen LHAV by Charlie (@Charlie7779) on CodePen.

但如果把樣式順序修改如下:

a:link {
  color: blue;
}
a:visited {
  color: purple;
}
a:hover {
  color: aqua;
}
a:active {
  color: red;
}

這個超連結就可以表現出四種不同狀態的樣式。 先點擊以下範例的超連結,超連結的文字會變成紫色,但因為:hover與:active的樣式順序在:visited以下,所以當游標停留在連結上(狀態為:hover)時,文字會變成水藍色;而點下超連結(狀態為:active)時,文字會變成紅色:

See the Pen LVHA by Charlie (@Charlie7779) on CodePen.

規則衝突時,後發覆蓋先寫的樣式

舉個 🌰,假設以下兩種針對<p>的樣式設定位在同一份原始碼裡面:

p {
  color: red;
  background: blue;
}

p {
  color: yellow;
}

衝突的規則只有color,background不受影響,所以最後<p>的樣式會是「藍色背景、黃色文字」:

See the Pen css specificity by Charlie (@Charlie7779) on CodePen.

透過繼承得到的樣式,權重是 0-0-0-0-0

舉個 🌰,假設以下兩種樣式設定位在同一份原始碼裡面:

#parent {
  color: green;
}

h1 {
  color: red;
}

而 HTML 內容如下:

<html>
  <body id="parent">
    <h1>A Title</h1>
  </body>
</html>

<h1>從<body id="parent">繼承到的文字色彩樣式會被 CSS 樣式表中的h1覆蓋掉(樣式h1的權重是 0-0-0-0-1),<h1>A Title</h1>會是紅色:

See the Pen inherited styles by Charlie (@Charlie7779) on CodePen.

參考文件