否定擬似クラス、:not()の詳細度

まれに疑似クラス: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.

タイトルとURLをコピーしました