概要
:has()疑似クラスはCSSのIF文
- 子孫の状態を監視し、ルールに従って自分も含めて制御するよく言われるのは、:has()疑似クラスはCSSのIF文。まさにその通りで、条件を設定しその条件を満たせば子孫の要素に対してスタイルを制御することが可能になる。条件には、特定の子要素やクラス、IDなどを含むか含まないかなどは当然だけど、CSS の状態も含まれ、:hover,:activeなどに加え :focus, :checked, などのフォーム系、:target,:empty,やdetails系の:openなど多くあり、簡単なIF文なら:has()疑似クラスがあればJS使う必要はなくなった。特にフォーム系は昔はフォームパーツにフォーカスしたり、チェックしたりしても親に伝えるにはJSが必要だったけど、今は:has()疑似クラスを使えばCSSだけで判定できるようになった。
さらに厳密にいうと、子が親を制御できるようになったというより、子が先祖だけでなく、枝分かれの兄弟やいとこまで制御できるようになったという方が正確といえる。bodyを:has()疑似クラスの親にすれば理論上はすべての要素が、任意の子要素の制御対象になるからね。
:has()疑似クラスの簡単な紹介
- 簡単な紹介まだ:has()疑似クラスをよく知らないという方のために、MDNで紹介されている内容を引用して紹介してみよう。
たとえば、下記の様なHTMLがある。<header> <h1>とある王国の物語</h1> </header> <section> <article>領民のとるべき道は</article> </section> - 通常、こういう場合のCSSはh1とarticleの間隔はheaderとsectionで空けるのでh1にはマージンは入れない。
h1{ margin-bottom: 0; } - しかし、状況によってh1の直後にp要素のリードが付いたり付かなかったりする場合があるとする。
この場合、つまりh1の直後にp要素が来たらh1のマージンがゼロなのでp要素とくっついてしまう。そのためh1自身にマージンを追加して、直後のp要素との間隔を空ける必要がある。当然、p要素がない時はマージンはゼロにしないといけない。<header> <h1>とある王国の物語</h1> <p>今、ハズクラス疑似王国は物価高が極まり<br>領民は日々の生活にあえいでいた。</p> </header> <section> <article>領民のとるべき道は</article> </section> - そこで:has()疑似クラスの登場、下記のように記述することで、h1直下にp要素がある場合にマージンを調整することができるようになる。
h1:has(+ p) { margin-bottom: 20px; } - CSSのif文:has()疑似クラスを使えば、『もしもh1の直下にp要素が来たらマージンを追加する。』というまるでIF文のような設定を入れられるんだ。
これが『:has()疑似クラスはCSSのIF文』と呼ばれるゆえんだね。
他にもいくつかサンプルがあるのでMDNを見ておくと良いと思う。
MDNの:has()疑似クラス解説ページ:https://developer.mozilla.org/ja/docs/Web/CSS/Reference/Selectors/:has
:has()疑似クラスができないこと
- 不可能はないような:has()疑似クラス、だけどできないこともそりゃああります。無敵の:has()疑似クラス、だけどできないことがあるんだよ。
たとえば:has()疑似クラスは、マウスオーバーには対応していても、クリックのようなイベントには対応してない。そもそもCSSには『クリックされた状態を保持する』仕組みがほぼないからね。
近いものには:focusや:checkedなどがあるけど、クリックと違い、:focusはマウスが外れると元に戻ってしまう。:activeもそうだね。
他にアンカー要素だとハッシュとtarget疑似クラスを使えば、なんとかなりそうだけど、スクロールの問題があり微妙(『ついにハッシュはGPSへ進化』で紹介したね)。
また他の要素button、details要素などを使う方法もあるけど、アンカー要素じゃなくて専用要素が必要などがあり、かなり微妙。
:checkedもinput要素が必要だからね。普通の文章に使うのはいろいろ問題がありそうだ。
早い話CSSには:hoverや:checkedはあるが:clickedという疑似クラスはないんだよねえ。そのうちできないかなあ。
で、現在の結論、クリックについてはやはりJSを併用するほうがスマート。何もJSはライバルってわけじゃないんだからどんどんお互いにサポートしあってスマートでエレガントなコードを書いていこう
そもそもCSSだけでやるんだ!ってそんな縛りはないので。
まあ、どうしてもCSSだけでクリック&:has()疑似クラスをやりたいって場合はdetailsか:checkedを使って何とかするしかないかもね。
で、次にその:checkedを使ったデモを紹介。