:has() は親セレクターではない。それは JavaScript を不要にする。

コード内で classList.toggle を検索してみてください。

おそらく、同じパターンのコードをいくつも見つけるでしょう。ユーザーがチェックボックスをクリックしたり、入力フィールドにフォーカスしたりしたとき、JavaScript を使って親要素のクラスを切り替えているはずです。これにより、CSS で親要素にスタイルを適用できるようにしています。

このコードのほとんどは削除できます。

:has() は「親セレクター」と呼ばれていますが、この呼び方は誤りです。:has() は条件をテストするものです。要素の内容を確認し、スタイルを適用するかどうかを判断します。

以下のようなチェックが可能です:

  • 子孫要素
  • 特定の兄弟要素
  • アイテムの数
  • 要素の不在

いくつかの例を挙げます:

• 画像を含んでいる場合にカードにスタイルを適用する: .card:has(img) { ... }

• チェックボックスがチェックされている場合に、行にスタイルを適用する: .option-row:has(input:checked) { background: var(--selected-bg); }

• アイテム数に基づいてグリッドレイアウトを変更する: .grid:has(> :nth-child(4)) { grid-template-columns: repeat(4, 1fr); }

最後の例は、純粋な CSS を使ってレイアウトを変更しています。これは DOM のライブな状態を読み取っています。

以前は、JavaScript を「メッセンジャー」として使う必要がありました。子要素から先祖要素のスタイルをトリガーすることはできなかったため、クラスをツリーの上位に移動させるためのリスナーを書かなければなりませんでした。

今や、そのメッセンジャーは不要になりました。

:has() を使えば、スタイルは常に正確です。初回のレンダリング時から機能し、ユーザーがブラウザの「戻る」ボタンを押したときにも機能します。状態の変化とスタイルの変化の間に遅延はありません。

以下の用途に活用してください:

  • フォームのバリデーション
  • リストの空の状態
  • 切り替え可能なパネル

ただし、:has() にはコストがかかることに注意してください。ブラウザは内部のセレクターを子孫要素に対して評価する必要があります。バリデーションやトグルといったほとんどの UI タスクでは、違いを感じることはないでしょう。

スクロール位置や、数千ものホバー状態といった、頻繁に変化するものへの使用は避けてください。

子要素からスタイルを制御するためだけにクラスを切り替えるのはやめましょう。代わりに :has() でその条件を表現できないか検討してください。CSS はスリムになり、JavaScript は不要になります。

:has() は Chrome、Firefox、Safari、Edge で動作します。

Source: https://dev.to/parsajiravand/has-isnt-a-parent-selector-it-deletes-javascript-4hej