この記事について
これまでCSSの詳細度についてなんとなくしか知らなかった人向けの解説。
属性セレクタの使い方とか基本的な事項はここで解説しませんので他の解説記事などを読んでください。
詳細度って何?
CSSのスタイルが競合したときに優先される順位(強さ)を表す点数。あまり知られていない隠しパラメータ的存在(?)
いくつかの例外
!important
基本的に他のどんな指定よりも優先される。インラインスタイル(style属性に直接記述)すら上書きできるので意図してそういう使い方をしたいならば良いかも。良い子は基本的に使わないようにするお約束。
[style*="color: red"] {
color: firebrick !important;
}
/* インラインスタイルにcolor:redが含まれている要素をcolor: firebrick; にしちゃうぞ */
:is() および :not()
:is() および :not()は疑似クラスだけど、詳細度の計算にはカウント(加点)されない。
※()の中で指定したセレクタはカウントされる。
div:not(.outer) {
color: blueviolet;
}
/* div と .outerを足した詳細度になります */
全称セレクタ(universal selector)
全称セレクタ(*)は要素セレクタの仲間っぽい感じするけど、詳細度の計算にはカウント(加点)されない。
*:first-child {
margin-top: 1rem;
}
/* 詳細度は :first-child の分だけ */
CSSコンビネータ(結合子)
CSSコンビネータは詳細度の計算にはカウント(加点)されない。
てゆうかCSSコンビネータってなに?というと > (子要素指定)とか +(隣接要素指定) とかのアレのことです。
名前はじめて知ったわ。
MDNには結合子って書いてあるしCSS結合子って呼んだ方がわかりやすい?
ul > li {
background-color: black;
}
/* ul と liを足した詳細度になります。 > は詳細度なし */
詳細度
下記のように4種類のグループのどれに所属するセレクタかによってランクがあります。
セレクタではありませんがインラインスタイルはグループSとしました。
詳細度表(強い順)
| グループ | セレクタの種類 | 記述例 |
|:-----------------:|:------------------|:------------------:|:------------------:|
| S | インラインスタイル | style="font-size: 20px;" |
| A | IDセレクタ | #id |
| B | クラスセレクタ・属性セレクタ・疑似クラス | .foo [href="https://"] :first-child |
| C | 要素セレクタ・疑似要素 | ul > li p ::before ::after |
具体例
セレクタ | 詳細度の数え方 | 詳細度強さ順 |
---|---|---|
h1 | C×1 | 5 |
h1 + p::first-letter | C×3 | 4 |
li > a[href*="en-US"] > .inline-warning | B×2 + C×2 | 3 |
li.foo:first-child | B×2 + C×1 | 4 |
.a1.a2.a3.a4 (...) .a98.a99.a100 | B×100 | 2 |
#identifier | A×1 | 1 |
Q&A
詳細度が同じ場合はどちらが優先されるの?
後に書いてあるスタイルで上書きされます。
ブラウザのユーザーエージェントとかあるけどスタイルの適用順はどうなっているの?
MDNによると下記の順番になるそうです。
- ユーザーエージェントのスタイルシートの宣言。例えば、他のスタイルが設定されていない場合に使用されるブラウザー標準のスタイルなど。
- ユーザースタイルシートの通常の宣言 (ユーザーが設定したカスタムスタイル)
- 作者のスタイルシートでの通常の宣言 (私たちウェブ開発者によって設定されたスタイルのことです)
- 作者のスタイルシートの重要 (important) な宣言
- ユーザーのスタイルシートの重要 (important) な宣言
関係ないけど疑似要素って:beforeとか::beforeとかどっちの書き方が正しいの?
今は::beforeの記法で書いてください。疑似クラスと区別するためです。昔は:beforeでもよかったのでどっちで書いても適用はされるみたいです。
idセレクタを11個使えば1100ポイントだからインラインスタイル(style="")に勝てるんだね?
理論上はそうみたいですね...現実的にそんな指定しないと思いますが試しにやってみてもいいかもしれません。
すみません。私がポイント制と誤解していましたが、下のランクのセレクタ指定をどれだけ増やしても上位ランクのセレクタを上書きできません。
例として、 .foo や [href="https://"] といったBランクのセレクタを100個増やしても1000個増やしても、一つのidセレクタ(Aランク)には勝てません。
本当かどうか実験してみた
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p id="goo" class="a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab">idが勝つならblack</p>
<div id="aa">
<div id="bb">
<div id="cc">
<div id="dd">
<div id="ee">
<div id="ff">
<div id="gg">
<div id="hh">
<div id="ii">
<div id="jj">
<div id="kk" style="color: blue;">
styleが勝つならblue
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<style>
#goo {
color:black;
}
.a1.a2.a3.a4.a5.a6.a7.a8.a9.aa.ab {
color: firebrick;
}
#aa #bb #cc #dd #ee #ff #gg #hh #ii #jj #kk {
color: orange;
}
</style>
</html>
結果
理論通りS > A > B の強さはセレクタの個数によっては覆りませんでした(!)