CSSの優先順位を知ろう
あなたは「CSS」の意味を知っていますか?
「CSS」とは、カスケーディング・スタイル・シート(Cascading Style Sheets)の略称です。
スタイルやシートはなんとなくわかるけど...カスケード(Cascad)って何だろう?
今回はそんなCSSの"C"にあたるカスケードを紐解いていきたいと思います。
記事の内容
CSSの優先順位についてわかる
目次
カスケード
そもそも「カスケード(Cascad)」は何という意味なんでしょうか?
「IT用語辞典 e-Words」では、次のように直訳しています。
カスケードとは、何段も連なった小さな滝のこと。転じて、同じものがいくつも数珠つなぎに連結された構造や、連鎖的あるいは段階的に物事が生じる様子を表す。
「連結された構造」や「段階的、連鎖的な様子」を指す言葉として用いられるようですね。ここからCSSでのカスケードは次のような意味で使われるようです。
Webページの見栄えを定義するCSS(Cascading Style Sheet)で、ある要素に適用されるスタイルを、大域的に定義されたものから局所的に定義されたものへと順番に引き継ぎながら適用していくことをカスケードあるいはカスケーディングという。
つまり
ある要素に対し複数のスタイルが競合するとき、優先度の低いルールから高いルールへ段階的に適用すること
と言えそうです。なんとなく「カスケード」というものが分かってきた気がします。
しかし、言葉だけだとやっぱりイメージが付きづらい...
そこで、これを図にしてみましょう。
カスケードのイメージ図
図を滝のように階段状にしてみました。
図のようにカスケードのルールには、1.重要性、2.詳細度、3.記述順の3つがあります。これらは滝の下にあるものほど優先度の高いルールになっており、上にあるルールを無効にします。
カスケードの優先順位(高い順)
- 重要性 (Importance)
- 詳細度 (Specificity)
- 記述順 (Source order)
では、ここからカスケードの3つのルールについて詳しく説明します。
段階に沿って、まず「記述順」からみてみましょう。
記述順 (Source order)
記述順とは...
詳細度が同じ場合に、「後(下)に書かれたコード」が優先されるというルールです。
例えば以下のように、要素 p に対して collar を適用したコードが二つある場合、後のコードが優先されて青色になります。
<p>文字の色はこうなります</p>
p {collar: #ff0000;}
p {collar: #0000ff;}
文字の色はこうなります
このルールはCSSのファイル内だけでなく、HTMLに読み込んだCSSの順番にも適用されています。
例えば以下のように、CSSがリンクタグや @import でHTMLに読み込まれた場合でも、この中で後に記述されたCSSの優先度が高くなります。
<style>
body {background: #fff;}
</style>
<link rel="stylesheet" type="text/css" href="https://〜〜〜"/>
<link rel="stylesheet" type="text/css" href="https://〜〜〜"/>
<style>
@import url("〜〜〜");
@import url("〜〜〜");
〜〜〜〜〜
</style>
<link rel="stylesheet" type="text/css" href="https://〜〜〜"/>
実は、はてなブログでデザイン表示がうまくいかなくなる原因の一つがコレです。
例えば、デザインCSSを書き換えてもフッタに書いたCSSが邪魔をしていたなど...
この「はてなブログのCSS記述順」に関しては以下の記事で説明をしています。
詳細度 (Specificity)
CSSを書いていると「後に記述したのに、前にあるコードが適用された」といったことがあると思います。
これは前に記述したセレクタが、後に記述したセレクタより高い詳細度を持っているため起こる現象です。
この「詳細度 (Specificity)」とはどういったものなのでしょうか?
MDNでは次のように説明しています。
詳細度は CSS 宣言が適用される際の重みであり、一致するセレクターそれぞれの種類の数によって特定されます。複数の宣言が同じ詳細度であれば、 CSS の中で最後に宣言されたものが要素に適用されます。詳細度は同じ要素に対して複数の宣言が行われている場合のみ適用されます。
簡単にすると
詳細度とは、セレクタの「数」と「ランク(種類)」によって決まる"重み"のことです。
このセレクタの「数」と「ランク」が同じ場合は、記述順で優先順位が決まります。
例えば、セレクタの「数」が異なる場合は
「数」が異なる場合
<div class="sample_class1">
<p class="sample_class2">文字の色はこうなります</p>
</div>
.sample_class1 p.sample_class2 {collar: #ff0000;}
p.sample_class2 {collar: #0000ff;}
文字の色はこうなります
この場合、.classの数が多い上の記述が優先され
文字は、後に記述した青色ではなく、前に記述した赤色になります。
また、セレクタの「ランク(種類)」が異なる場合は
「ランク(種類)」が異なる場合
<p id="sample_id" class="sample_class">文字の色はこうなります</p>
p#sample_id {collar: #ff0000;}
p.sample_class {collar: #0000ff;}
文字の色はこうなります
この場合、.classより#idの方がセレクタのランクが高いので
文字は、後に記述した青色ではなく、前に記述した赤色になります。
このように優先順位は、セレクタの数が多いほど高く、セレクタのランクが高いほど高くなります。
詳細度のランク:style属性 > #id > .class > タイプ
詳細度の高さを大雑把に分けるとこのようになります。
これが基本となります。左にある要素がより優先順位の高いランクに位置しています。
下の表は、これをより細かくランク分けした表になります。
A.B.C.Dがセレクタのランクを表しており、それらをピリオド.でしきって点数化しています。このランクはA>B>C>Dの順に優先順位が高くなります。
詳細度のランク
セレクタ名 | 使用例 | A | B | C | D | 点数 |
---|---|---|---|---|---|---|
全称セレクタ | * | 0 | 0 | 0 | 0 | 0.0.0.0 |
要素型セレクタ | p | 0 | 0 | 0 | 1 | 0.0.0.1 |
擬似要素 | ::first-letter | 0 | 0 | 0 | 1 | 0.0.0.1 |
クラスセレクタ | .sample | 0 | 0 | 1 | 0 | 0.0.0.1 |
擬似クラス | :link | 0 | 0 | 1 | 0 | 0.0.1.0 |
属性セレクタ | p[target=“_blank"] | 0 | 0 | 1 | 0 | 0.0.1.0 |
idセレクタ | #id | 0 | 1 | 0 | 0 | 0.1.0.0 |
style属性 | <p style=“”> | 1 | 0 | 0 | 0 | 1.0.0.0 |
詳細度の計算例
使用例 | A | B | C | D | 点数 |
---|---|---|---|---|---|
.hatena-module-category a:hover::before | 0 | 0 | 2 | 2 | 0.0.2.2 |
nav#slide-menu li:hover > a | 0 | 1 | 1 | 3 | 0.1.1.3 |
この計算はセレクタの数がパッと見でわかるうちはいいのですが、多くなると数えて比較するのが面倒になるので以下の「Specificity Calculator」というツールを使うのが便利です。
Specificity Calculator(CSSの詳細度計算ツール)
余談:よくある間違い
点数表記はソフトウェアのバージョン表記のように、ランク毎にピリオド.で仕切り表記します。
よくこの点数を#idが100点、.classが10点というように表記してしまいがちですが、厳密に言えばこの説明は違います。
理由は、ランクCのセレクタが10点以上集まっても、ランクBのセレクタ1点の優先順位が高いためです。
例えば、以下のような2つのセレクタがある場合
10進数で計算すると上:312点、下:356点ですが、実際は上:3.1.2、下:2.15.6で計算されるのでidセレクタの多い上が優先されます。
(まぁこんなに長いセレクタまずお目にかからないですが...)
div#main div#main-inner article#entry-13574176438018771963.entry.hentry.test-hentry.js-entry-article.date-first.autopagerize_page_element.chars-11200.words-1000.mode-html.entry-odd div.entry-inner header.entry-header h1 .entry-title a.entry-title-link.bookmark
このように、ランクごとに点数計算をするのが詳細度の正しい計算方法になります。
重要性 (Importance)
ここまでの見てきたルールを無効にする特別な宣言が、 !important です。
例えば以下のように、#idセレクタやstyle属性などの優先度の高い指示をしても、 !important はそれらを無効にできます。
<p id="sample_id" style="collar: #ffff00;">文字の色はこうなります</p>
p {collar: #ff0000 !important;}
p#sample_id {collar: #0000ff;}
文字の色はこうなります
しかし、この方法を使うには注意が必要です。
それは、 !important の優先度が高すぎるという事です。
例えば、 !important を広域な要素に使った場合、その要素に当てはまる狭域な要素の変更は記述順や詳細度ではできません。
仕方ないので、その部分にも !important を使う事になります。
そうすると、またその条件内にある要素に変更したい場所が現れて...(以後繰り返し)
遂には !important 同士が競合するという事になります。
こうなってしまうと結局、記述順の並び替え、詳細度の調整に立ち返る事になるので、本末転倒。意味がありません。
それも、これまで適当にやってきた !important を全てやり直すわけですから...
考えただけで恐ろしいですね。
「大きすぎる力は使い方を誤ると悲劇をもたらす」という言葉がピッタリの !important
なので極力、これまで利用してきた記述順、詳細度のルールのみでCSSを書くよう心がけましょう。
- 記述順を利用する。追加するコードは後に記述する。
- 詳細度を利用する。セレクタのランクまたは数で調整をする。
この2つのルールをマスターすることが優先順位を使いこなす一番の近道です。
まとめ
- カスケードとは、優先順位のルールが段階的に適用される事
- 大前提として後に書いたコードが優先される(記述順)
- 詳細度とはセレクタの「数」と「ランク」で決まる優先順位
- 詳細度の点数計算はランク毎におこなう
- !importantは優先度が高すぎるので使用はなるべく控える
どうだったでしょうか?
僕もまだまだ半端者ですが、優先順位の理解を深めたおかげで無駄に悩むことが減ったように感じます。
基本ってやっぱり大事ですね。
同じように、なんとなくCSSを書いていたという人や、知ってたけど使いこなせていなかったという人に、この記事が役に立てば幸いです。
参考資料
- カスケード(カスケーディング)とは - IT用語辞典 e-Words
- カスケードと継承 - ウェブ開発を学ぶ | MDN
- 詳細度 - CSS: カスケーディングスタイルシート | MDN
- CSSの優先順位を理解しよう(!importantの使い方も) | creive
- 【CSS】カスケード(スタイルの優先順位) | Hazu Labo
- CSSセレクタの優先度を手軽に計算して比較できるツール「Specificity Calculator」 | 寝ログ
- ご存知、ないのですか?CSSの優先順位
- CSSの優先順位を自在に適応させる方法 | Mobile First Marketing Labo
- 【初心者向け】CSSセレクタとは?セレクタの種類や指定方法を解説!(基礎編) : ビジネスとIT活用に役立つ情報
- 知っておきたいCSS セレクタの優先順位・詳細度・継承 - WEBST8のブログ
- CSSが効かないときの優先順位チェック(2)~id・class編 - Naifix