2 つのルールが同じ要素に適用されたとき、どちらが勝つか決めるのが CSS 詳細度(Specificity)です。これを理解していないと !important を乱発したり、スタイルが効かない原因をひたすら探し続けることになります。このガイドでは計算方法、よくある落とし穴、そして計算ツールを使った競合の素早いデバッグ方法を説明します。

CSS 詳細度をオンラインで確認 →

詳細度の計算方法

詳細度は (a, b, c) の 3 つの数値で表します:

何を数えるか
aID セレクター(#id
bクラス(.class)、属性([type])、擬似クラス(:hover
c要素(divp)、擬似要素(::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 は何個クラスがあっても勝ちます。

比較ルール:左から順に

  1. a を比較。大きい方が勝ち。同じなら b
  2. b を比較。大きい方が勝ち。同じなら c
  3. 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() を使うプロパティの詳細度は、変数の定義元ではなくセレクターで決まります。

詳細度の競合をデバッグする手順

スタイルが効かないときの典型的な手順:

  1. DevTools → 要素を検証 → Styles パネルを確認
  2. 打ち消し線のあるルールは上書きされている — ホバーで勝者を確認
  3. 競合する 2 つのセレクターを CSS 詳細度計算ツール に貼り付けてスコアを比較
  4. 負けているセレクターの詳細度を上げるか、構造を見直す

修正例

/* 問題:このルールが効いていない */
.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 ツール

手計算不要、計算ツールで即確認

ZeroTool の CSS 詳細度計算ツール は任意のセレクターを解析し、正確な (a, b, c) スコアを返します。各寄与部分をハイライト表示し、複数のセレクターを並べて比較できます。サインアップ不要、ブラウザ上で動作します。

CSS 詳細度計算ツールを試す →