【CSS】:has()を試してみたら思った以上に便利だった

こんにちは!
フロントエンドエンジニアのあまんちゅです。

今回は CSS の擬似クラス関数 :has() を試してみたので、その基本的な内容やユースケースを紹介します。

これまで JavaScript で対応していた処理を CSS だけで実現できるようになりつつあり、とても注目しています。
簡単に言うと「特定の子要素を持つ親要素を選択できる」セレクタで、非常に便利です。

:has()の基本

  • 形式は A:has(B)
  • 「A 要素の中に B があるときに A を選択」する意味になる
  • 複数条件を組み合わせたり、擬似クラスと併用することも可能

例:article 内に .featured クラスを持つ画像がある場合のみ適用。

article:has(img.featured) {
  /* スタイル */
}

ユースケース集

フォームのバリデーション

必須フィールドが未入力の場合に、フォーム全体を赤枠にする例です。
従来は「エラーがあったら JS でクラスを追加」していましたが、CSS だけで実現できます。

form:has(input:invalid) {
  border: 2px solid red;
}
必須入力が未入力のときフォーム全体が赤枠になる例

チェックボックスでボタンの状態を変える

利用規約に同意するとボタンの色が変わり、有効化がわかる UI です。
状態管理を JavaScript に任せなくても、CSS だけで「チェックあり → ボタン有効」を実現できます。

label:has(input:checked) + button {
  background: blue;
  color: white;
}
チェックボックスにチェックするとボタンの色が変化する例

カードの中に画像があるときだけ余白を調整

これまでは「子要素の有無で修飾クラスを付与」していましたが、:has() で不要になります。
例では、テキストのみの場合は余白がありますが、画像があると余白をなくすことができます。

.card:has(img) {
  padding-bottom: 0;
}
画像の有無によってカード下部の余白が変わる例

リストアイテムが多いときだけ2カラム表示

リストの項目数が多い場合に自動的にレイアウトを変更する例です。
従来は「項目数を JavaScript でカウント → クラスを追加」していましたが、CSS だけで実現できます。

ul:has(li:nth-child(n+10)) {
  columns: 2;
  column-gap: 2rem;
}
リストアイテムが多いときは2カラム表示になる例

ポイント

  • 主要ブラウザ(Chrome / Edge / Safari / Firefox)は最新版で対応済み
  • DOM が大きいページや、ネストが深く複雑なセレクタを組み合わせる場合はレンダリングコストに注意

まとめ

今回は4つのユースケースを紹介しましたが、他にも活用できる場面は多くあると思います。
特に「子要素の有無で親要素のスタイルを変えたい」場面では非常に便利です。
ただし、大規模な DOM や複雑なセレクタの乱用はパフォーマンスに影響する可能性があるため、適切に使っていきたいと思います。

このブログ内では、他のメンバーが書いた CSS に関する記事 も多数公開していますので、ぜひあわせてご覧ください。

この記事を気に入ったら

あまんちゅ

あまんちゅ

2023年夏入社です。 海の上の橋を渡るのが好きです。

この人が書いた記事を見る >>