詳細度(Specificity)
CSSの詳細度(Specificity)は、同じ要素に対して複数のスタイルが競合したとき、どのスタイルが優先されるかを決定する仕組みです。セレクタの種類に応じてポイントが計算され、ポイントが高いスタイルが適用されます。
詳細度の計算方法
詳細度は、セレクタに含まれる要素の種類ごとにポイントを加算して計算します。ポイントは4つのレベルに分かれています。
| レベル | 対象 | ポイント | 例 |
|---|---|---|---|
| A(最高) | インラインスタイル(style属性) | 1,0,0,0 | style="color: red;" |
| B | IDセレクタ | 0,1,0,0 | #header |
| C | クラス / 属性 / 擬似クラス | 0,0,1,0 | .active, [type="text"], :hover |
| D(最低) | 要素型 / 擬似要素 | 0,0,0,1 | div, p, ::before |
全称セレクタ(*)、結合子(+, >, ~)、否定擬似クラス(:not())自体にはポイントがありません。ただし、:not()の括弧内のセレクタはポイントに加算されます。
計算例
| セレクタ | A | B | C | D | 詳細度 |
|---|---|---|---|---|---|
p | 0 | 0 | 0 | 1 | 0,0,0,1 |
p.fighter | 0 | 0 | 1 | 1 | 0,0,1,1 |
#yagami | 0 | 1 | 0 | 0 | 0,1,0,0 |
div#yagami .active | 0 | 1 | 1 | 1 | 0,1,1,1 |
#yagami ul li.highlight | 0 | 1 | 1 | 2 | 0,1,1,2 |
style="..." | 1 | 0 | 0 | 0 | 1,0,0,0 |
ポイントの比較はレベルA → B → C → Dの順に行います。レベルAが同じ場合にのみBを比較し、Bも同じならCを比較します。レベルDがいくら多くても、レベルCの1ポイントに勝つことはありません。
詳細度の点数は10進数ではない
ネットの記事や参考書の中には「IDセレクタは100点、クラスセレクタは10点」のように10進数の数値として説明しているものがありますが、これは正確ではありません。詳細度の各レベルは独立しており、下位レベルのポイントがいくら多くても上位レベルの1ポイントを超えることはできません。
以下の例で確認してみます。IDセレクタ1つと、クラスセレクタ11個を並べたセレクタを比較します。
style.css
/* 詳細度: 0,1,0,0 */
#yagami {
color: red;
}
/* 詳細度: 0,0,11,0(クラスが11個あっても IDの1ポイントに勝てない) */
.a.b.c.d.e.f.g.h.i.j.k {
color: blue;
}
index.html
<div id="yagami" class="a b c d e f g h i j k">八神庵</div>
10進数の計算であれば、クラス11個(10点 × 11 = 110点)はID 1個(100点)を超えるはずですが、実際には赤文字になります。これは各レベルの点数が繰り上がらない仕組みだからです。IDセレクタの『0,1,0,0』に対して、クラスセレクタがいくつ並んでも『0,0,11,0』のままであり、レベルBの1ポイントをレベルCから超えることはできません。
この仕組みはソフトウェアのバージョン表記(セマンティック・バージョニング)と似ています。バージョン『2.0.0』は『1.99.99』より新しいのと同じように、上位レベルが優先されます。
サンプルコード
同じ要素に複数のセレクタが競合した場合、詳細度の高いセレクタのスタイルが優先されます。
style.css
/* 詳細度: 0,0,0,1 */
p {
color: blue;
}
/* 詳細度: 0,0,1,0(クラスセレクタは要素型セレクタより高い) */
.fighter-name {
color: crimson;
}
/* 詳細度: 0,1,0,0(IDセレクタはクラスセレクタより高い) */
#yagami {
color: purple;
}
index.html
<p>この段落は青色です</p> <p class="fighter-name">草薙京</p> <p class="fighter-name" id="yagami">八神庵</p>
「八神庵」は p(blue)、.fighter-name(crimson)、#yagami(purple)の3つのルールに該当しますが、IDセレクタの詳細度が最も高いため、purple が適用されます。
!importantについて
!important が付けられた宣言は、詳細度の計算を無視して最優先で適用されます。
#yagami {
color: purple;
}
.fighter-name {
color: crimson !important;
}
上の例では、IDセレクタ(#yagami)の詳細度のほうが高いですが、.fighter-name に !important が付いているため crimson が適用されます。
!important 同士が競合した場合は、通常の詳細度ルールに戻って比較されます。
#yagami {
color: purple !important;
}
.fighter-name {
color: crimson !important;
}
両方に !important が付いている場合は、IDセレクタの詳細度が高い #yagami の purple が適用されます。
:rootを使った詳細度の引き上げ
:root 擬似クラスは html 要素を指しますが、擬似クラスであるためレベルCに分類されます。html が要素型セレクタで 0,0,0,1 なのに対し、:root は 0,0,1,0 になります。
この性質を利用すると、!important を使わずにセレクタの詳細度を引き上げることができます。
/* 詳細度: 0,0,1,0 */
.fighter-name {
color: crimson;
}
/* 詳細度: 0,0,2,0(:root が加わりクラスセレクタだけでも上書きできる) */
:root .fighter-name {
color: blue;
}
:root .fighter-name の詳細度は 0,0,2,0 になり、.fighter-name 単体の 0,0,1,0 を上回ります。外部のCSSライブラリや他の開発者が書いたスタイルを上書きしたいとき、!important に頼らずに対処できる手法として知られています。
さらに詳細度を上げたい場合は :root を重ねることもできます。
/* 詳細度: 0,0,3,0 */
:root:root .fighter-name {
color: blue;
}
:root を2つ重ねると 0,0,3,0 になります。IDセレクタを使わずに詳細度を段階的に引き上げられるため、!important の一歩手前の手段として活用できます。
詳細度が同じ場合の優先順位
詳細度がまったく同じセレクタが競合した場合は、CSSファイル内で後に記述されたルールが優先されます。
.fighter-name {
color: crimson;
}
.fighter-name {
color: blue;
}
どちらも詳細度は 0,0,1,0 で同じですが、後に書かれた blue が適用されます。この仕組みは「カスケード(Cascade)」と呼ばれ、CSSの名前の由来にもなっています。
よくあるミス
!importantの多用
!important はスタイルの競合を解消する便利な手段ですが、多用すると「!importantでしか上書きできない」状態に陥り、CSSの保守が困難になります。
.fighter-name {
color: crimson !important;
}
/* 後から色を変えたくなっても !important なしでは上書きできない */
#yagami .fighter-name {
color: purple;
}
上の例では、#yagami .fighter-name の詳細度(0,1,1,0)のほうが高いですが、!important が付いた crimson を上書きできません。詳細度が高いセレクタを使って解決するほうが、CSSの設計としては健全です。
IDセレクタの詳細度を見落とす
IDセレクタの詳細度は非常に高いため、後からクラスセレクタで上書きしようとしても効きません。
/* 詳細度: 0,1,0,0 */
#yagami {
background-color: #2c0033;
}
/* 詳細度: 0,0,3,0(クラスを3つ重ねても ID に勝てない) */
.team .roster .fighter-name {
background-color: #ffffff;
}
クラスセレクタをいくつ重ねても、IDセレクタの詳細度(レベルB)を超えることはできません。IDセレクタが使われている箇所を上書きするには、同じIDセレクタを含めるか、!important を使う必要があります。
対応ブラウザ
CSSの詳細度はCSS仕様の基本的な仕組みであり、CSSに対応するすべてのブラウザで同じ計算ルールが適用されます。
Android Browser
2.1 以降 ○※ バージョン情報は MDN に基づいています。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。