CSSの詳細度の説明方法が変わってきた?改めて見直してみよう!
CSSって簡単だけど難しい?
皆さん、CSSは簡単ですか?難しいですか? 私が思うに、CSSは簡単だから難しいのです。
CSSって、ルールは単純ですよね? なんとなく書いても大体は問題なく表示されますよね?
それが原因!「CSSなんとなく書けちゃう問題」が原因なのです。
そこで、CSSの詳細度についてまとめてみようと思います。 ですが、改めて調べてみると、私が勉強していた当時と説明の仕方が変わっていることに気づきました。
そういうわけで、本記事ではCSSの詳細度について、ふんわりと理解している方向けに書いていますが、最近の詳細度の説明の仕方がどう変わってきたについても記載します。
CSSのセレクタの種類
セレクタの詳細度を説明するためには、セレクタの種類の説明が必要になります。 セレクタの種類によって計算方法が違うため、まずはセレクタの種類を列挙します。
ユニバーサルセレクタ
ユニバーサルセレクタは全ての要素が対象となります。 セレクタは*(アスタリスク)で表記します。
/* ユニバーサルセレクタ */ * { /* 全てのタグの文字色が黒になる */ color: #000; }
タイプセレクタ
タイプセレクタは要素が対象となります。 セレクタはタグ名で表記します。
<!-- h1タグ --> <h1>h1タグだよ</h1>
/* タイプセレクタ */ h1 { /* h1タグの文字色が黒になる */ color: #000; }
クラスセレクタ
クラスセレクタはclass属性を持つ要素が対象となります。 セレクタは.(ドット)に任意の文字列を続けた形で表記します。
<!-- class属性に class-dayo を指定したh1タグ --> <h1 class="class-dayo">class属性を持っているタグだよ</h1>
/* クラスセレクタ */ .class-dayo { /* class属性に class-dayo を持つ要素の文字色が黒になる */ color: #000; }
IDセレクタ
IDセレクタはid属性を持つ要素が対象となります。 セレクタは#(シャープ)に任意の文字列を続けた形で表記します。
<!-- id属性に id-dayo を指定したh1タグ --> <h1 id="id-dayo">id属性を持っているタグだよ</h1>
/* IDセレクタ */ #id-dayo { /* id属性に id-dayo を持つ要素の文字色が黒になる */ color: #000; }
属性セレクタ
属性セレクタは特定の属性を持つが対象となります。 セレクタは属性名と属性値で表記します。
<!-- src属性に image.jpg を指定したimgタグ --> <img src="image.jpg">
/* 属性セレクタ */ img[src] { /* src属性を持つimg要素の高さが10pxになる */ height: 10px; } img[src="image.jpg"] { /* src属性に image.jpg を持つimg要素の高さが100pxになる */ height: 100px; }
疑似クラス
疑似クラスは要素が特定の状態にある時が対象となります。 セレクタは要素名と:(コロン)に続く特定の文字列で表記します。
<!-- aタグ --> <a href="#">aタグだよ</a>
/* 疑似クラス */ a:hover { /* aタグにマウスがホバーした時に文字色が黒になる */ color: #000; }
疑似要素
疑似要素は要素ではない部分が対象となります。 セレクタは要素名と:(コロン)2つに続く特定の文字列で表記します。
「要素ではない部分が対象」というのは若干わかりづらいですが、 具体的な例を挙げると、 p::first-letterと指定すると、pタグ内の文字列の1文字目が対象となります。 p::beforeと指定すると、pタグ内の行頭に疑似的な要素を追加します。
<!-- pタグ --> <p>pタグだよ</p>
/* 疑似要素 */ p::before { /* pタグの行頭に「疑似要素だよ」という文字が表示される */ content: '疑似要素だよ'; }
セレクタの詳細度による優先順位
詳細度とは、セレクタの強弱の度合のことです。
詳細度は、よく3桁の数字として表現されます。
3桁目 | 2桁目 | 1桁目 |
---|---|---|
IDセレクタ | クラスセレクタ 属性セレクタ 疑似クラス | タイプセレクタ 疑似要素 |
各セレクタが当る数が、要素の詳細度ということになります。 詳細度が高い順に、CSSのスタイルが適応されます。
例えば、
p.hoge.fuga p#hoge
というセレクタがあったとしたら、
前者は「詳細度:021」 後者は「詳細度:101」
となり、後者の方が詳細度が高いということになります。
「3桁の数字」という言葉の罠
最近は3桁の数字という表現は御幣があるため、他の言い方に変わってきたようです。
何故御幣があるかというと、
例えば、 p#hogeが「詳細度:101」なら p.c1.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12 という風に、クラスセレクタを10個以上書いたらどうなるでしょうか。
クラスセレクタが12個あるので、桁数が繰り上がって「詳細度:121」になると思いませんか?
残念!なりません!
p.c1.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12よりも、 p#hogeの方が詳細度は高いのです。
詳細度はバージョン番号として考える
最近は3桁の数字ではなく、abcとして分類されているようです。
a | b | c |
---|---|---|
IDセレクタ | クラスセレクタ 属性セレクタ 疑似クラス | タイプセレクタ 疑似要素 |
そして、バージョン番号のようにドットつなぎの「a.b.c」という風に計算するという説明に変わっているみたいです。
先程の例をバージョン番号として考えると、 p.c1.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12は「詳細度:0.12.1」 p#hogeは「詳細度:1.0.1」 となり、バージョン番号が高いのはp#hogeということになります。
この考え方なら、「クラスセレクタを大量に書けばIDセレクタを打ち消せるのでは!?」という誤解はしなくて済みますよね。
ユニバーサルセレクタは0点
詳細度のabcの表の中に、ユニバーサルセレクタがないことにお気づきでしょうか。 実は、ユニバーサルセレクタは a=0, b=0, c=0 であり、なんの加点にもならないのです。 ・・・そもそもそんなに使う機会がないセレクタですけどね。
IDセレクタでスタイルは当てない
ここまでの詳細度の計算方法を知ると、IDセレクタが如何に高い詳細度を持っているかがわかるかと思います。
どこかでIDセレクタを使われてしまったら、それを打ち消すためには、新たにIDセレクタを増やしたり、打ち消したいセレクタよりも後方にCSSの記述をする、などの面倒な対応が必要になります。
しかも、IDは一意の存在であるため、HTML文書の中で1箇所にしか使えません。 HTMLを変更してスタイルを当てるという方法もやり辛いです。
そういった観点から、IDセレクタではスタイルを当てないのがベターな方法です。
style属性は詳細度の範囲外
各セレクタの詳細度の計算方法を説明しましたが、HTMLのタグにstyle属性を書いた場合は詳細度がいくつなのか、気になっている人も多いことでしょう。
style属性は、無条件で詳細度が最も高いものとして扱われます。
この仕様を知ると、気軽に「style属性に直書きしちゃおう♪」なんて、とてもじゃないけど思えませんよね。 IDセレクタでさえ手を焼いているのに、それ以上の難敵です。
style属性でスタイル調整、ダメゼッタイ。
「!important」地獄
style属性さえも打ち消せてしまう最強の存在が!importantです。 !important はセレクタではなく、プロパティの後ろに書きます。
<!-- style属性で文字色を赤に指定 --> <p style="color:red;">pタグだよ</p>
p { /* style属性の文字色赤を、!importantで文字色を青に指定 */ color: blue !important; }
さて、上記の例で、!important を使って文字色を青にしてしまいました。
!important地獄の始まりです。
!importantを打ち消すためには、!importantでしか打ち消せません。 CSSの詳細度がより高いセレクタを書いて、そこに!importantを書く、という具合ですね。
じゃあ、それを打ち消すには・・・? もっともっと詳細度の高いセレクタにするしかないですよね?
HTMLの構造上「これ以上セレクタの詳細度を高くできない!」という限界値まで到達したら? CSSの記述位置を最後部にして上書くしか方法がありません。
!importantでスタイル上書き、ダメゼッタイ。