2 つのルールが同じ要素に適用されたとき、どちらが勝つか決めるのが CSS 詳細度(Specificity)です。これを理解していないと !important を乱発したり、スタイルが効かない原因をひたすら探し続けることになります。このガイドでは計算方法、よくある落とし穴、そして計算ツールを使った競合の素早いデバッグ方法を説明します。
詳細度の計算方法
詳細度は (a, b, c) の 3 つの数値で表します:
| 列 | 何を数えるか |
|---|---|
a | ID セレクター(#id) |
b | クラス(.class)、属性([type])、擬似クラス(:hover) |
c | 要素(div、p)、擬似要素(::before) |
インラインスタイル(style="")はこの 3 列より上位に位置し、最も高い優先度を持ちます。
具体例
/* 詳細度:(0, 0, 1) — 要素 1 つ */
p { color: red; }
/* 詳細度:(0, 1, 0) — クラス 1 つ */
.intro { color: blue; }
/* 詳細度:(0, 1, 1) — クラス 1 つ + 要素 1 つ */
p.intro { color: green; }
/* 詳細度:(1, 0, 0) — ID 1 つ */
#header { color: purple; }
/* 詳細度:(1, 1, 0) — ID 1 つ + クラス 1 つ */
#header .nav { color: orange; }
2 つのルールが競合する場合、大きい数値が勝ちます。(1, 0, 0) は (0, 99, 99) より高い — ID は何個クラスがあっても勝ちます。
比較ルール:左から順に
aを比較。大きい方が勝ち。同じならbへbを比較。大きい方が勝ち。同じならcへcを比較。大きい方が勝ち。それでも同じならソース順が決め手 — 後に書かれたルールが勝ち
/* (0,2,0) vs (0,1,2) */
/* a: 同じ;b: 2 > 1 — 1 行目が勝ち */
.nav .link { color: red; } /* (0,2,0) — 勝ち */
.nav li span { color: blue; } /* (0,1,2) */
詳細度の階層
低い順から高い順:
要素/擬似要素 → クラス/属性/擬似クラス → ID → インラインスタイル → !important
(0,0,1) (0,1,0) (1,0,0) 最上位
!important は詳細度の値ではなく、宣言を通常のカスケード外に引き上げます。!important を上書きするには同等以上の詳細度を持つ別の !important が必要です。
よくある落とし穴
ユニバーサルセレクター * の詳細度はゼロ
* は何の数値も加算しません。*.active は .active と同じ (0,1,0) です。
:not() 自体はゼロ、引数は有効
:not(p) はゼロを追加しますが、括弧内の p は (0,0,1) を追加します。div:not(.hidden) は (0,1,1) です。
:is()、:where()、:has()
:is()— 引数リスト中の最も高い詳細度を取る:where()— 常にゼロ(リセット CSS に便利):has()—:is()と同様
/* (0,1,0) — :is() が .active の詳細度を取る */
:is(.active, p) { color: red; }
/* (0,0,0) — :where() は常にゼロ */
:where(.active, p) { color: red; }
CSS 変数は詳細度に影響しない
var() を使うプロパティの詳細度は、変数の定義元ではなくセレクターで決まります。
詳細度の競合をデバッグする手順
スタイルが効かないときの典型的な手順:
- DevTools → 要素を検証 → Styles パネルを確認
- 打ち消し線のあるルールは上書きされている — ホバーで勝者を確認
- 競合する 2 つのセレクターを CSS 詳細度計算ツール に貼り付けてスコアを比較
- 負けているセレクターの詳細度を上げるか、構造を見直す
修正例
/* 問題:このルールが効いていない */
.card p { font-size: 14px; } /* (0,1,1) */
/* これが勝っている */
#content p { font-size: 16px; } /* (1,0,1) */
/* 対処法 1:詳細度を上げる */
#content .card p { font-size: 14px; } /* (1,1,1) */
/* 対処法 2(推奨):ID をクラスに変えてフラットに保つ */
.content .card p { font-size: 14px; } /* (0,2,1) */
長期的には CSS でID セレクターを使わないのが最善です。
詳細度の実践的な指針
詳細度をフラットに保つ。 セレクターを (0,1,0) ~ (0,2,1) 程度に抑えると、プロジェクトが大きくなるほど恩恵を受けます。
CSS では ID を避ける。 ID は JavaScript のフックとしてのみ使用し、CSS ではクラスに置き換えます。#header nav → .site-header .nav。
@layer でカスケードを管理する。 CSS @layer を使えば詳細度とは独立してカスケード順序を制御できます。
@layer base, components, utilities;
@layer base {
#header { color: black; } /* (1,0,0) */
}
@layer utilities {
.text-white { color: white; } /* (0,1,0) — それでも勝つ */
}
!important は最終手段。 まずセレクターの再構築を試みましょう。
関連 CSS ツール
- CSS 単位コンバーター — px、rem、em、vw などを変換
- CSS 変数ジェネレーター — デザイントークンを管理
- CSS Grid ジェネレーター — グリッドレイアウトをビジュアルで構築
手計算不要、計算ツールで即確認
ZeroTool の CSS 詳細度計算ツール は任意のセレクターを解析し、正確な (a, b, c) スコアを返します。各寄与部分をハイライト表示し、複数のセレクターを並べて比較できます。サインアップ不要、ブラウザ上で動作します。