まれに疑似クラス:not()が予想とちがう振る舞い(効いてほしくないところに効く)をすることがあったので、cssの詳細度についてきちんと調べ直しました。
素直な感想としては、:not()ってやばいやつだったんだな。。というところです。では本文をどうぞ。
基本的なCSSの詳細度について
ブラウザがサイトを表示するとき、要素にどのスタイルを適応させるか、の計算に使われているのが詳細度です。
詳細度という言葉は聞いたことがなくても、「IDで指定したスタイルはクラス指定より優先される」のように感覚で知っていると思います。
Id – Class – Type で計算
詳細度の計算は、ID列 – Class列 – Type列 で行います。複数のclassで指定しても1つのID指定にかなわない通り、詳細度は ID列 > Class列 > Type列 の順に高くなります。
Class列にはclassはもちろん、属性(type=”number” href=”hoge.html” など)や疑似クラス(:nth-child() 、:hoverなど)も含まれます。
Type列は、pやdivなどの要素や疑似要素(before,after)です。
div#hoge > p.foo{
---
}
/* 1 - 1 - 2 */
例外的な詳細度となる疑似クラスたち
疑似クラスはClass列に加点されると書きましたが、:not()、:is()、:has()、:where()。つまり引数にID、Class、Typeをとる疑似クラスは例外として扱われます。
:where()をのぞく、:not()、:is()、:has()は、それ自身は詳細度に影響しませんが、引数が詳細度計算の対象となります。下の例ではID列が1,Class列が0、Type列が1となります。
div:not(#hoge){
--
}
/* 1-0-1 */
つまり、引数にIDがあればID列に1ポイント加算され、classがあればClassに1加算されます。
ちなみに、:where()の詳細度は 0-0-0 です。
無意味なセレクタが許容されている:not()
基本的に、CSSセレクタは該当するものを絞り込んでいきますが、それとは逆に該当するものを除外する:not()は否定疑似クラスと呼ばれます。
否定疑似クラスは、存在しない要素や無意味な指定を許容されています。たとえば全てを除外する :not(*){ — } なんて無駄なスタイルを書いても怒られません。
もちろんIDを10個もった要素を除外する、なんてスタイルを作っても問題ありません。するとID列が10という高い詳細度をもつセレクタの出来上がりです。
:not(#hoge#hoge1#hoge2#hoge3#hoge4#hoge5#hoge6#hoge7#hoge8#hoge9){
font-size:100px
}
/* 詳細度 10-0-0 */
!importantを使わずにとにかく詳細度を高めたいときには役立つでしょう。実際の業務で使うかどうかは別として、知識として知っていて損はないと思います。
以下は確認用にいろいろ指定してみたcodepenです。
See the Pen Untitled by Takashi Abe (@TakeshiAbe) on CodePen.