• CSSセレクタの優先順位は重要度、詳細度、記述順で判断する

CSSセレクタの優先順位は重要度、詳細度、記述順で判断する

公開日: 執筆:佐藤

同じ要素の同じプロパティへ複数のCSS宣言が適用されるときは、後に書かれた宣言が常に優先されるわけではありません。最初に!importantとスタイルシートの出所を比べ、条件が同じならセレクタの詳細度を比べます。記述順を使うのは、そこまで同じ場合です。

詳細度は、セレクタが要素をどれだけ限定しているかを、ID、クラスや属性、要素名の種類ごとに数えたものです。数字をすべて足さず、強い区分から順に比べます。

CSSの優先順位は三段階で決まる

CSS 2.1のカスケード仕様は、同じ要素とプロパティへ当てはまる宣言を、次の順で並べます。

  1. 宣言の重要度とスタイルシートの出所
  2. セレクタの詳細度
  3. 宣言が書かれた順序

詳細度だけを計算しても、!importantの有無や出所が違えば、優先順位は決まりません。反対に、重要度と出所が同じなら、詳細度が高いセレクタの宣言が優先されます。詳細度も同じ場合は、後に書かれた宣言が優先されます。

確認する対象は、CSSファイル全体ではありません。表示が合わない要素と、一つのプロパティを決め、その組み合わせに適用される宣言だけを比べます。colorの問題を調べるときに、同じ規則内のmarginまで優先順位へ含める必要はありません。

詳細度はstyle属性、ID、クラス、要素の列に分ける

CSS 2.1では、詳細度をa-b-c-dの四つに分けます。

区分 数えるもの 例
a HTMLのstyle属性から指定された宣言 style="color: red"
b IDセレクタ #notice
c クラスセレクタ、属性セレクタ、擬似クラス .message、[title]、:hover
d 要素名、擬似要素 p、::first-line

全称セレクタ*は、詳細度へ加えません。子孫を示す空白、子を示す>、隣接する兄弟を示す+などの結合子も、四つの区分には数えません。

四つの数字は、左から順に比べます。合計値にはしません。0-1-0-0のIDセレクタと0-0-2-0のクラス二つを比べると、最初に差が出るIDの列で前者が優先されます。

三つのセレクタを同じ要素で比べる

次のHTMLには、要素名、クラス、IDを一つずつ指定しています。これは詳細度の計算を示すための例であり、サトラボの実案件ではありません。

<p id="notice" class="message">受付時間を確認してください。</p>

同じcolorへ、三つの規則を指定します。

p {
  color: black;
}

.message {
  color: blue;
}

#notice {
  color: red;
}

詳細度は次のようになります。

セレクタ a b c d 詳細度
p 0 0 0 1 0-0-0-1
.message 0 0 1 0 0-0-1-0
#notice 0 1 0 0 0-1-0-0

三つの宣言は、重要度と出所が同じです。IDの列で差が付くため、#noticeのcolor: redが優先されます。.messageを後へ移しても、詳細度が低いままなら結果は変わりません。

同じ詳細度なら後に書かれた宣言が優先される

次の二つは、どちらもクラスセレクタ一つで、詳細度は0-0-1-0です。

.message {
  color: blue;
}

.attention {
  color: red;
}

同じ要素がclass="message attention"を持つ場合は、後に書かれた.attentionの宣言が優先されます。記述順が決め手になるのは、重要度、出所、詳細度が同じときです。

外部CSSファイルの読み込み順も、最終的な記述順へ影響します。上書き用の規則を別ファイルへ置く場合は、そのファイルが後から読み込まれていることだけでなく、競合するセレクタの詳細度も確認します。

!importantは詳細度を上げる記法ではない

!importantを付けた宣言は、通常の宣言より先に比較されます。これはセレクタのIDやクラスを増やして詳細度を上げる処理ではありません。

.message {
  color: blue !important;
}

#notice {
  color: red;
}

この二つが同じ作成者のスタイルシートにある場合、.messageの宣言が優先されます。通常宣言どうしなら#noticeの詳細度が高くても、重要度の比較が先だからです。

作成者の!important宣言どうしなら、その中で詳細度を比べます。CSS 2.1では、利用者が指定した!important宣言は、作成者の!important宣言よりも優先されます。利用者が必要な文字サイズや配色を指定できる余地を、作成者側の詳細度だけで判断してはいけません。

表示を直すたびに!importantを追加すると、次の修正でも重要宣言どうしを競わせることになります。先に競合する宣言を特定し、セレクタと読み込み順を直せるか判断します。

継承は詳細度の競争に参加しない

親要素へ指定したcolorが子要素へ伝わることと、子要素へ直接適用される宣言が競合することは別です。CSS 2.1の指定値に関する規則では、カスケードで値が決まればその値を使い、決まらない場合に、継承するプロパティなら親要素の算出値を使います。

親要素のIDセレクタが高い詳細度を持っていても、その詳細度を子要素が引き継ぐわけではありません。子要素へp { color: black; }が直接適用されるなら、親から継承する色ではなく、子要素の宣言が使われます。

表示が変わらないときは一つのプロパティから追う

CSSが上書きされないときは、対象の要素とプロパティを一つに固定します。次に、その組み合わせへ適用される宣言を集め、次の順で比べます。

  1. セレクタが対象要素に一致しているか
  2. !importantの有無とスタイルシートの出所が同じか
  3. style属性、ID、クラス・属性・擬似クラス、要素・擬似要素の順で詳細度を比べたか
  4. 詳細度まで同じなら、どちらが後に書かれているか
  5. 直接適用される宣言がない場合は、継承または初期値か

最初の一手は、表示を直したい要素について、変わらないプロパティを一つ選ぶことです。競合する宣言を二つ並べ、重要度、詳細度、記述順のどこで優先順位が決まったかを書き出してください。原因が分かれば、セレクタを必要以上に長くしたり、!importantを追加したりせずに修正できます。

戻る