CSSでいう「特異点」は、「詳細度」または「Specificity」と呼びます。簡単にいうと、同じ要素に複数のCSSが当たったとき、どの指定を優先するかを決める点数のことです。
CSSでは、単純に「下に書いたCSSが勝つ」わけではありません。実際には、カスケード、詳細度、読み込み順、!important、インラインスタイルなどが関係します。MDNでも、詳細度は同じ要素に複数の宣言が当たったときに使われる重みとして説明されています。
結論
CSSの優先順位は、基本的に次の順番で決まります。
!importantがあるか- インラインスタイルか
- セレクタの詳細度が高いか
- 同じ詳細度なら後に書かれているか
ただし、現在のCSSでは @layer なども関係するため、詳細度だけで全部が決まるわけではありません。CSSのカスケードは、出所、レイヤー、詳細度、記述順などを組み合わせて最終的な値を決定します。
詳細度の基本ルール
CSSの詳細度は、次のような考え方で計算します。
#main .card p {
color: red;
}
この場合、
#main → IDセレクタ
.card → クラスセレクタ
p → 要素セレクタ
となります。
詳細度は、ざっくり次の強さです。
インラインスタイル
↓
IDセレクタ
↓
クラス・属性・疑似クラス
↓
要素・疑似要素
↓
全称セレクタ
詳細度の点数イメージ
CSSの詳細度は、よく次のように表します。
インライン - ID - クラス系 - 要素系
例です。
p {
color: blue;
}
これは要素セレクタだけなので、
0 - 0 - 0 - 1
です。
.text {
color: red;
}
これはクラスセレクタなので、
0 - 0 - 1 - 0
です。
#title {
color: green;
}
これはIDセレクタなので、
0 - 1 - 0 - 0
です。
<p style="color: orange;">テキスト</p>
これはインラインスタイルなので、
1 - 0 - 0 - 0
です。
実例で理解する
HTMLが次のようになっているとします。
<p id="lead" class="text">こんにちは</p>
CSSが次の場合、文字色は何色になるでしょうか。
p {
color: blue;
}
.text {
color: red;
}
#lead {
color: green;
}
答えは green です。
理由は、詳細度が次のようになるからです。
p → 0 - 0 - 0 - 1
.text → 0 - 0 - 1 - 0
#lead → 0 - 1 - 0 - 0
IDセレクタである #lead が一番強いため、green が適用されます。
同じ詳細度なら後に書いたCSSが勝つ
次の例を見てください。
.text {
color: red;
}
.text {
color: blue;
}
どちらも同じ .text なので、詳細度は同じです。
この場合は、後に書かれた blue が適用されます。
.text {
color: blue;
}
つまり、同じ強さなら後勝ちです。MDNでも、同じ詳細度の場合は後に現れた宣言が適用されると説明されています。
IDセレクタはかなり強い
次のCSSでは、どちらが勝つでしょうか。
#main {
color: red;
}
.content .box .text {
color: blue;
}
答えは #main です。
クラスが3つあっても、IDセレクタ1つのほうが強いです。
#main → 0 - 1 - 0 - 0
.content .box .text → 0 - 0 - 3 - 0
ここで注意したいのは、詳細度は普通の足し算ではないということです。
クラス10個 = ID1個
にはなりません。
IDはIDの列、クラスはクラスの列で比較されます。
クラスをたくさん重ねると管理しにくくなる
例えば、次のようなCSSは詳細度が高くなりすぎます。
body .wrapper .main .content .article .card .title {
font-size: 24px;
}
このような指定をすると、あとから上書きするのが大変になります。
例えば、単純にこう書いても負けます。
.title {
font-size: 20px;
}
理由は、前のセレクタのほうがクラス数が多く、詳細度が高いからです。
CSSが効かない原因の多くは、この「詳細度の上げすぎ」です。
!important は詳細度より強い
次の例では、どちらが勝つでしょうか。
#title {
color: red;
}
.text {
color: blue !important;
}
答えは blue です。
通常であればIDセレクタの #title が強いですが、!important が付いているため .text が勝ちます。
ただし、!important を多用すると、後からCSSを修正しづらくなります。
.text {
color: blue !important;
}
これをさらに上書きするには、また !important を使う必要が出てきます。
.other {
color: green !important;
}
このように、!important の連鎖が起きるとCSSが破綻しやすくなります。
インラインスタイルはかなり強い
HTMLに直接書くスタイルは強いです。
<p class="text" style="color: red;">テキスト</p>
.text {
color: blue;
}
この場合、red が適用されます。
通常のCSSよりも、HTMLに直接書かれた style 属性のほうが優先されます。インラインスタイルは通常の作成者スタイルより強く扱われることがMDNでも説明されています。
詳細度に関係しないもの
次のものは、詳細度を上げません。
* {
color: red;
}
全称セレクタ * は詳細度に影響しません。
div > p {
color: red;
}
この > のような結合子も詳細度には影響しません。
div p {
color: red;
}
空白の子孫セレクタも、それ自体は詳細度を持ちません。
詳細度に影響するのは、主にID、クラス、属性、疑似クラス、要素、疑似要素です。
疑似クラスの詳細度
疑似クラスは、クラスと同じ強さです。
a:hover {
color: red;
}
この場合、
a → 要素
:hover → 疑似クラス
なので、
0 - 0 - 1 - 1
です。
よく使う疑似クラスには、次のようなものがあります。
:hover
:focus
:first-child
:nth-child()
:not()
:is()
:where()
:has()
:not() の注意点
:not(.active) {
color: red;
}
:not() 自体が強くなるというより、中に入っているセレクタの詳細度が影響します。
この場合は .active の分が反映されます。
:not(.active) → 0 - 0 - 1 - 0
:is() の注意点
:is(#main, .content, p) {
color: red;
}
:is() は、中にあるセレクタのうち、最も詳細度が高いものが反映されます。
この場合、#main が含まれているため、かなり強いセレクタになります。
:is(#main, .content, p) → 0 - 1 - 0 - 0
便利ですが、意図せず詳細度が高くなることがあります。
:where() は詳細度を0にできる
:where() はかなり便利です。
:where(.card .title) {
font-size: 24px;
}
:where() の中にクラスや要素を書いても、詳細度は0になります。
つまり、あとから上書きしやすいCSSを書けます。
.title {
font-size: 20px;
}
このように、後から普通のクラス指定で上書きできます。
現代のCSS設計では、詳細度を上げすぎないために :where() がよく使われます。
@layer と詳細度の関係
最近のCSSでは、@layer も重要です。
@layer base, components, utilities;
@layer base {
button {
color: black;
}
}
@layer components {
.button {
color: blue;
}
}
@layer utilities {
.text-red {
color: red;
}
}
@layer は、CSSを層に分けて優先順位を管理する仕組みです。
詳細度で無理やり勝たせるのではなく、レイヤー単位で管理できます。MDNでは、カスケードレイヤーは詳細度と戦わずにCSSの優先順位を整理できる仕組みとして説明されています。
ただし、初心者のうちはまず次の順番で理解すれば大丈夫です。
普通のCSS
↓
詳細度
↓
後勝ち
↓
必要なときだけ @layer
CSSが効かないときの確認順
CSSが効かないときは、次の順番で確認すると原因を見つけやすいです。
- セレクタが対象のHTMLに本当に当たっているか
- 同じプロパティが別のCSSで上書きされていないか
- 相手の詳細度が高くないか
- 後から読み込まれているCSSがないか
- インラインスタイルが付いていないか
!importantが使われていないか@layerの影響を受けていないか
特にWordPressでは、テーマCSS、プラグインCSS、カスタムCSS、ブロックエディターのCSSが重なるため、詳細度の理解が重要です。
悪い例
body .site .main .content .box .card .card-title {
color: red;
}
このように長すぎるセレクタは、後から修正しにくくなります。
さらに、次のように上書きしたくても効かないことがあります。
.card-title {
color: blue;
}
詳細度が足りないからです。
良い例
.card-title {
color: red;
}
または、部品単位で分かりやすくします。
.card {
padding: 20px;
}
.card-title {
font-size: 24px;
color: red;
}
.card-text {
font-size: 16px;
}
このように、クラスを中心にシンプルに書くと、上書きしやすくなります。
上書きしたい場合の正しい考え方
たとえば、次のCSSがあるとします。
.article .card-title {
color: red;
}
これを上書きしたい場合、次のように書くと勝てます。
.article .card-title {
color: blue;
}
同じ詳細度で後に書けば勝ちます。
または、状態を表すクラスを追加します。
.card-title.is-active {
color: blue;
}
この場合、クラスが2つになるため、詳細度が少し上がります。
.card-title.is-active → 0 - 0 - 2 - 0
!important を使ってもよい場面
基本的には避けたほうがよいですが、使ってよい場面もあります。
例えば、ユーティリティクラスです。
.u-hidden {
display: none !important;
}
このように、「どんな場合でも非表示にしたい」という明確な目的がある場合は使えます。
ただし、デザイン調整のたびに !important を使うのは避けたほうがよいです。
悪い例です。
.title {
font-size: 28px !important;
color: red !important;
margin-bottom: 20px !important;
}
この書き方を続けると、CSS全体の管理が難しくなります。
WordPressでよくある例
WordPressでは、次のようなCSSが効かないことがあります。
h2 {
color: red;
}
理由は、テーマ側で次のように指定されている場合があるからです。
.entry-content h2 {
color: blue;
}
この場合、
h2 → 0 - 0 - 0 - 1
.entry-content h2 → 0 - 0 - 1 - 1
なので、.entry-content h2 が勝ちます。
上書きするなら、同じかそれ以上の詳細度で書きます。
.entry-content h2 {
color: red;
}
または、特定のページだけ変えたいなら、ページ固有のクラスを使います。
.page-id-123 .entry-content h2 {
color: red;
}
詳細度を上げすぎないコツ
CSSは、強く書くよりも、上書きしやすく書くほうが大切です。
おすすめは次の考え方です。
IDセレクタはできるだけ使わない
クラス中心で書く
セレクタを長くしすぎない
!importantを多用しない
同じ詳細度なら後に書いて上書きする
必要に応じて@layerを使う
特に、普段のCSSではIDよりもクラスを使うほうが管理しやすいです。
覚えておくべき優先順位
実務では、まずこれだけ覚えておくと十分です。
!important
↓
インラインスタイル
↓
IDセレクタ
↓
クラス・属性・疑似クラス
↓
要素・疑似要素
↓
後に書いたCSS
ただし、正確にはCSSのカスケード全体では、出所、重要度、レイヤー、詳細度、記述順などが関係します。W3CのCSS Cascading and Inheritance Level 5でも、カスケードと継承によって各要素のプロパティ値が決定されることが説明されています。
まとめ
CSSの特異点、つまり詳細度とは、同じ要素に複数のCSSが当たったとき、どのスタイルを優先するかを決める仕組みです。
初心者がまず覚えるべきことは、次の3つです。
IDは強い
クラスは扱いやすい
同じ強さなら後に書いたCSSが勝つ
そして、CSSが効かないときは、すぐに !important を使うのではなく、まず詳細度を確認することが大切です。
実務では、詳細度を高くすることよりも、あとから修正しやすいCSSを書くことのほうが重要です。クラス中心でシンプルに書くと、WordPressやWeb制作でもトラブルが少なくなります。
