CSSを設計するときに、特定の子要素を持つ親要素のみスタイルを当てたい場合どうしていましたか?例えば、画像を持つカードと画像を持たないカードでデザインを切り分けたい場合です。
一般的な対応は「jQueryの:has()を利用して親要素にクラスを付与する」でしょうか。
もしくは、「HTMLに出力する時点でクラスを付与できるように工夫し、複数パターンのスタイルを用意する」でしょうか。
どのような対応でも一手間かかったものが、CSS擬似クラスだけで実現できるようになりました。
私は首を長くして待っていたこの機能をご紹介します。
:has擬似クラスの使い方
基本的な使い方は擬似クラスと同じになります。
.card:has(img) {
/* img要素を持つ.cardのスタイルを記述します */
}
特定の要素(クラスなども指定可能)を持つ親要素にスタイルを実装する機能です。
記述はシンプルですが、CSSだけで完結できるところに大きな価値があります。
:not()擬似クラスと組み合わせることもできます(あまり実用的ではないと思います)。
.card.not(:has(img)) {
/* img要素を持たない.cardのスタイルを記述します */
}
冒頭で例に出した、カードの画像を持つ持たないでスタイルを切り替えるデモを用意しました。
デモのHTMLを確認するとわかりますが、画像の有無によってHTMLにクラスを付与などは行なっておりません。
単純な記述ですが、CSSでロジックを扱えるようになりました。
これまでの対応と比べると、コストが大幅に下がりますね。
2022年9月時点でのブラウザ対応状況
Chrome、Edgeは105(2022年9月時点での最新版)であれば対応していますね。
Safari(iOS含む)は 15.4以上であれば対応済み。
しかしFirefoxが対応していませんね、今のところ今後の対応予定もなさそうです。
現場で使う場合は注意が必要です。
いますぐ使いたい場合はポリフィルを使いましょう。
もしくはCSSの@supportsルールで切り分けましょう。
@supports selector(:has(*)) {
/* :has対応ブラウザならばこの中のスタイルを適応します。 */
}
jQueryの:hasを使用している環境下では注意が必要
jQueryで:has()を用いていると、挙動がおかしくなることが報告されているようです。
単純にjQueryの:has()を使っているからダメというわけではなく、特定の条件下で起きるようです。
ブラウザ、CSS、jQueryそれぞれで対応しなきゃね、と話されているようですが、対応の具体的な予定はまだ出ていない模様です(2022年9月現在)。
まとめ
CSS界隈では渇望されていた機能がついに使える!と盛り上がっていたのですが、現時点で安易に使うのはやめた方がよさそうです。
テストコードを書いた感想としては、同じ機能を実装するコストがすごく下がったことを実感できたので、ぜひ現場でも使いたいと思いました。
CSSは力技でもなんとかなることが多いですが、知っていれば実装コストを下げられる機能があることを知ってもらいたくて紹介しました。
:has()に関しては、また続報があれば紹介するかもしれません。