この記事の目次
CSS詳細度とは
「CSSを書いたのに色が変わらない」の大半は、別のルールの詳細度(specificity)のほうが高いことが原因です。詳細度は、同じ要素に複数のルールが当たったとき、どれを採用するかを決めるための点数です。MDN では、ID・クラス系・要素系の3つの列で比べると説明されています。この記事では、数え方、実際に動かした結果、そして !important に頼らず整理する方法を扱います。
基本(数え方)
詳細度は「ID – クラス – 要素」の3列で表し、左の列から順に比べます。右の列がいくら多くても、左の列が1つ多いほうが勝ちます。
| セレクタの種類 | 例 | 加点 |
|---|---|---|
| IDセレクタ | #box |
1-0-0 |
| クラス・属性・疑似クラス | .note [type="text"] :hover |
0-1-0 |
| 要素・疑似要素 | p ::before |
0-0-1 |
| ユニバーサル・結合子 | * > + |
加点なし |
次の例では、#box .note が 1-1-0、p.note が 0-1-1 なので、前者が勝ちます。
p { color: black; } /* 0-0-1 */
.note { color: blue; } /* 0-1-0 */
p.note { color: green; } /* 0-1-1 */
#box .note { color: red; } /* 1-1-0 ← 勝つ */
詳細度が同じなら、あとに書いたルールが勝ちます。:is() と :has() は自身では加点せず、引数の中で最も高いものが加点されます。:where() は常に 0-0-0 で、上書きしやすい土台のCSSを書くときに便利です。
サンプルコード(実行結果つき)
<style>
.note { color: blue; }
#box .note { color: red; }
:where(#box) .w { color: purple; } /* 0-1-0 */
.w { color: orange; } /* 0-1-0、あとに書いたので勝つはず */
.imp { color: gray !important; }
#box .imp { color: red; }
</style>
<div id="box">
<p class="note" id="a">A</p>
<p class="note w" id="b">B</p>
<p class="imp" id="c">C</p>
</div>
B は class="note w" なので、.note(青)、#box .note(赤、1-1-0)、:where(#box) .w(紫、0-1-0)、.w(オレンジ、0-1-0)が全部当たります。この中で最も高いのは #box .note の 1-1-0 なので、.w のオレンジや :where の紫ではなく赤になります。:where(#box) は #box の1点を数えない点が、.w と同点になる理由です。C は !important が付いた灰色が、IDを含む赤より優先されます。
動作確認(検証環境と結果)
- 環境: Windows 11 / Microsoft Edge 154(Chromium系、headless)/
render.ps1で描画し、getComputedStyleの値を取得 - ファイル:
C:Tempks2techtestst2specificity.html
| 要素 | 取得した color |
|---|---|
A(.note + #box .note) |
rgb(255, 0, 0)(赤) |
B(.note.w) |
rgb(255, 0, 0)(赤) |
C(!important) |
rgb(128, 128, 128)(灰) |
IDを含むルールが、クラスだけのルール(.w のオレンジや :where 経由の紫)を上回ることを確認できました。
CSS詳細度の注意点
- 数字は「10進数の桁」ではありません。クラスを11個並べても、IDの1つには勝てません。
- インラインスタイル(
style="")は、通常のルールより強く働きます。JavaScriptで直接styleを書き換えたものが勝つ原因になります。 - 継承された値は、要素に直接当たったルールには勝てません。親に強いルールを書いても、子に直接の指定があればそちらが優先されます。
- 詳細度の前に、「どのオリジンか」「!important か」「カスケードレイヤーか」で優先順位が決まります。レイヤー内のスタイルは、レイヤーに入れていないスタイルより弱くなります。
CSS詳細度でよくあるミス
- 上書きしたいのに、元のルールより弱いセレクタを書いている。DevTools の Styles パネルで、打ち消し線が付いた側を確認するのが近道です。
- IDセレクタでスタイルを書き始め、あとから上書きのためにIDを重ねて詳細度競争になる。
- 困ったときに !important を付ける。次に上書きしたい人も !important を付けるしかなくなります。
- CMSやライブラリのCSSに負けたとき、セレクタを長くしすぎる。
:where()やレイヤーで整理するほうが保守しやすいです。
ブラウザ対応・バージョン
IDやクラスの詳細度は昔から共通です。:is() :where() :has() のような新しい疑似クラスは、対応ブラウザやバージョンが異なります。使う前に MDN の Browser compatibility と can I use で、対象ブラウザを確認してください。
CSS詳細度のチェックリスト
- DevTools で、効いていないルールの打ち消し線と、勝っているルールを確認したか。
- 上書きのためにセレクタを長くする前に、元のルールを直せないか検討したか。
- IDセレクタをスタイルに使わず、クラス中心にしているか。
- !important は、外部CSSの上書きなど理由のある場面だけに限っているか。
CSS詳細度のFAQ(よくある質問)
Q. クラスを重ねれば、IDに勝てますか?
A. 勝てません。左の列から比べるため、IDが1つあれば、クラスの数に関係なくIDのほうが強くなります。
Q. :where() はいつ使いますか?
A. リセットCSSやコンポーネントの初期スタイルなど、「あとで簡単に上書きしたい」ルールに向きます。詳細度が 0 になります。
Q. 同じ詳細度なら、どちらが勝ちますか?
A. 読み込み順があとのほうです。CSSファイルの読み込み順にも注意してください。
筆者の見解(CSS詳細度)
詳細度は暗記するより、「できるだけ低く、均一に保つ」設計の考え方として使うのがよいと考えます。クラス1つ(0-1-0)に揃えておけば、上書きは「あとに書く」だけで済み、!important もほとんど要らなくなります。効かないときにセレクタを足す前に、いったん DevTools で原因を見る習慣を付けるのがおすすめです。
