:has() と :not() を使って親にも子にもリストを持たない単独のリストだけにスタイルを当てる
- 公開日
- タグ
- css
マークアップを変更できないライブ会場(現場のこと)において、CSS のタイプセレクタと擬似クラスで対応するのは難解なパズルを解いているようで楽しい。
今回は表題の通り単独のリスト、つまり自身がリスト要素の中に入っておらずかつ子要素にもリストを持たないようなリスト要素にスタイルを当てたい。
<!-- ようはこういったリスト要素である -->
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
親にも子にもリスト要素がないので、下記のようなリストにはいずれの階層であってもスタイルを当てたくない。
<ul>
<li>
Item 1
<ul>
<li>
Item 1-1
<ul>
<li>Item 1-1-1</li>
</ul>
</li>
</ul>
</li>
</ul>
Item 1 は子要素にリストを持つ。Item 1-1 は自身がリストの子リストであり、さらに子リストを持つ。Item 1-1-1 は子リストは持っていないが、自身が子リストである。
実食
パッと思いつくのは
ul:not(:has(ul))
というセレクタだろう。しかしこれは「子要素に
ul
を持たない
ul
」がマッチするので、自身が子リストであることは考慮されずうまくいかない。
ではさらに親要素の条件を加えて、
:not(li) ul:not(:has(ul))
ならどうだとなるが、これもうまくいかない。
Item 1-1-1 の ul
に着目すると、親要素に
li
も ul
もあるゆえか
:not(li)
だけでは不十分なようだ。
というわけでファイナルアンサーは
:not(li) > ul:not(:has(ul))
である。
li
の直接の子要素でなく、かつ子要素に
ul
を持たない
ul
をセレクタで表現すれば良いと言うわけだ。今回は
ul
で書いているがもちろん ol
でも動く。
:has() はすごいけど気をつけたい
2023 年 9 月 4 日現在 :has()
のブラウザ対応は Firefox
を残すのみとなっている。
:has() CSS relational pseudo-class | Can I use... Support tables for HTML5, CSS3, etc
:has()
は以前の記事「関係擬似クラス :has()
でホバーしている要素の前の隣接要素を指定する」でも紹介したとおりとてもパワフルだ。構造さえわかっていれば識別のための
CSS クラスや ID
が不要になる。マークアップを変更できない現場や、識別子を付与するためにプロパティをバケツリレーしなくてはならないウェブアプリの現場では大いに力を発揮するだろう。
しかしあくまで構造依存なので、HTML
が変わってしまうとスタイルは当たらない。また、スタイリングの全容を知るために
HTML と CSS の両方を読む必要があり、慣れない人にとっては
:has()
のような擬似クラスの利用は障壁となるだろう。
:not()
との組み合わせでより顕著になり、複雑なセレクタは理解の妨げになってしまう。
当然だがちゃんと識別子を使ったほうが設計として堅牢だ。:has()
を使う他ない場合や、そうする方が既存の設計を壊さない場合など、利用する際は十分な理由を見つけたい。
何事も用法用量を守って、という点は忘れないでいよう。