CSSセレクタ詳細度の理解を深める

社内勉強会のメモ

# CSSセレクタの詳細度とは

## 仕様

https://www.w3.org/TR/selectors-3/#specificity

仕様にもある通り、「詳細度」というのは

> selector's specificity

なので、「セレクタの詳細度」のこと。

**詳細度は計算できる。**

## MDN

https://developer.mozilla.org/ja/docs/Web/CSS/Specificity

> 詳細度Specificityは、どの CSS プロパティが要素に最も関係があるか、すなわち適用されるかをブラウザーが決定する手段です。詳細度は様々な組み合わせの CSS セレクターで構成される一致規則に基づいています。

「ちゃんとプロパティを書いてるのに適用されない！」みたいになってDevToolsを開いてみたら、実際に当てたいプロパティに打ち消し線が入っている、みたいなことが起きうる原因。

※以下の文章の引用は、注釈が無い限りこちらのページからの引用となります。

# 基本

単品で比べた時のプロパティの優先度の高さの順番は以下の通り
（ここで「詳細度」と書いていないのは、厳密に言えば!importantとstyle属性はセレクタでは無いので、セレクタの詳細度とは別の仕様であるため）

```
高

0. !important
1. HTML上のstyle属性に書かれたプロパティ
2. IDセレクタ
3. クラスセレクタ、属性セレクタ、擬似セレクタ
4. 要素型セレクタ、擬似要素
5. CSSの記載順序がうしろのプロパティ

低
```

## !important

>  !important 規則がスタイル宣言で使われたとき、それが宣言リストのどこであっても、この宣言は CSS 内で作られたその他の宣言を上書きします。

セレクタの詳細度とは別の仕様で、他のあらゆるプロパティを上書きするので、最も優先度が高い。
同じプロパティに`!important`が記載された場合は、セレクタの詳細度が適用される。

**世紀末な無法地帯になるので使わないでください。**


## HTML上のstyle属性に書かれたプロパティ

> 要素に追加されたインラインスタイルは、常に外部スタイルシートの中のスタイルを上書きします

セレクタの詳細度とは別の仕様で、 `!important` 以外のプロパティを上書きするので、優先度が高い。

## IDセレクタ、クラスセレクタ、属性セレクタ、擬似セレクタ、要素型セレクタ、擬似要素

- IDセレクタ：`#hoge`
- クラスセレクタ：`.hoge`
- 属性セレクタ：`[name="hoge"]`
- 擬似セレクタ：`:hover`
- 要素型セレクタ：`div`
- 擬似要素：`::before`

これらがセレクタの詳細度の仕様で言及されているセレクタたち。

> 全称セレクター (*), 結合子 (+, >, ~, ' ', ||), 否定疑似クラス (:not()) は詳細度に影響を与えません。 (但し、 :not() の中で宣言されたセレクターは影響を与えます。)

# 詳細度の計算方法

## 考え方

セレクタたちは全員、詳細度の点数を持っている。
点数の種類は3つあり、そのセレクタの３つの数字を並べたものが詳細度になる。

モデルとしてはソフトウェアのセマンティックバージョンの表記と同じ。

```
セレクタ {
  プロパティ: 値;
}
```

というCSSの記法のうち、「セレクタ」部分に登場するセレクタたちの点数が、カギカッコの中の「プロパティ」たちの詳細度となる。


## セレクタの点数

仕様書とは異なる表記だが、わかりやすさのためここではセマンティックバージョンと同じように表記する。

|  セレクタ   |  点数  |
|:----|---:|
|  ID   |  1.0.0  |
|  クラス、属性、擬似   |  0.1.0  |
|  要素型、擬似要素   |  0.0.1  |
|  全称、結合子、否定擬似クラス<br/>（ただし否定擬似クラス内のセレクタは計算に含める）   |  無視  |

## 例

```hoge.css
.hoge.piyo {
  background-color: blue;
}

.hoge {
  background-color: red;
}
```

というファイルがあったとして、上下のそれぞれの詳細度は

- 上：クラスセレクタ（0.1.0）が2個なので0.2.0。
- 下：クラスセレクタ(0.1.0）が1個なので0.1.0。

通常であればcssは後に書いたプロパティが優先されるが、このファイルの場合上に書かれたセレクタの方が詳細度が高いので、上の`background-color: blue;`が適用される。

![スクリーンショット 2019-11-07 16.20.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132179/d43efd28-262d-4f1e-2963-319455562074.png)

<details><summary>HTMLファイルを表示する</summary><div>

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>CSSの詳細度</title>
  <style>
    .hoge {
      width: 200px;
      height: 200px;
    }

    .hoge.piyo {
      background-color: blue;
    }

    .hoge {
      background-color: red;
    }
  </style>
</head>
<body>
  <div class="hoge piyo"></div>
</body>
</html>
```
</div></details>

## 桁の壁を越えることはない

注意が必要なのは、これらの３種類の点数は、例え下の桁の数字が1000個集まっても詳細度として上の桁の点数に勝ることはないということ。
（最初「合計」という言葉を使って表記していましたが、語弊を招くと思い修正しました。）

```hoge.css
#hoge {
  background-color: green;
}

.hoge1.hoge2.hoge3.hoge4.hoge5.hoge6.hoge7.hoge8.hoge9.hoge10.hoge11.hoge12.hoge13 {
  background-color: red;
}
```

```html
<div id="hoge"
     class="hoge hoge1 hoge2 hoge3 hoge4 hoge5 hoge6 hoge7 hoge8 hoge9 hoge10 hoge11 hoge12 hoge13" >
  HOGE
</div>
```

仮にこういったコードがあったとしても、これの HOGE の背景色は `green` （id で指定している値）になる。

![スクリーンショット 2022-03-09 20.38.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132179/496b07c5-fad4-20ca-57d4-f7acdbe95c24.png)


つまりこの場合の id の詳細度は #hoge は 1.0.0 で、 下のクラスの連なりは 13 個あるから **1.3.0 ではなく** **0.13.0 である**、ということ。