has

子孫や後ろの兄弟要素の状態をもとに、要素を選べる疑似クラス。 JavaScriptでクラスを付け外ししていた「親を選ぶ」処理を、CSSだけで書けます。

今の書き方

チェックされたチェックボックスを含むかどうかで、行にスタイルを当てられます。 状態が変わればスタイルも自動で切り替わるため、JavaScriptは要りません。

tr:has(input[type="checkbox"]:checked) {
  background-color: #fef3c7;
}

以前の書き方

親要素を選ぶセレクターがなかったため、強調用のクラス(.is-checked)にスタイルを当てていました。 クラスは、JavaScriptでチェックボックスの変化を受け取り、行に付け外しします。 読み込んだ時点でチェックされている場合に備えて、最初の状態にも合わせておく必要があります。

tr.is-checked {
  background-color: #fef3c7;
}
for (const checkbox of document.querySelectorAll('tr input[type="checkbox"]')) {
  const row = checkbox.closest('tr')
  const update = () => row.classList.toggle('is-checked', checkbox.checked)
  update()
  checkbox.addEventListener('change', update)
}

置き換えるときの注意点

  • :has()の中に:has()は書けません。
  • :has()の中に疑似要素(::beforeなど)は書けません。
  • :has()の中のセレクターが1つでも無効だと、:has()全体が無効になります。 書き間違いや未対応のセレクターを混ぜると、ルールごと効かなくなります。
  • :has()は、子孫の状態が変わるたびに判定し直されます。 body:has(...)のように広い範囲を対象にすると判定の範囲も広がるため、できるだけ近い親要素に絞ります。

フォールバック

対象の5ブラウザはすべて対応済みなので、通常は古い書き方を残す必要はありません。 古いブラウザも支える必要がある場合は、以前の書き方のCSSと今の書き方のCSSを、別々のルールとして両方残します。 1つのセレクターリストにまとめると、:has()に対応していないブラウザではルール全体が無視されます。 JavaScriptは、:has()に対応していないブラウザでだけ動かします。

// :has() に対応していないブラウザでだけ、以前の書き方のクラスを付ける
if (!CSS.supports('selector(:has(*))')) {
  const checkboxes = document.querySelectorAll('tr input[type="checkbox"]')
  for (const checkbox of checkboxes) {
    const row = checkbox.closest('tr')
    const update = () => row.classList.toggle('is-checked', checkbox.checked)
    update()
    checkbox.addEventListener('change', update)
  }
}

Browser Support

  • Chrome

    v105+
    2022-09-02
  • Edge

    v105+
    2022-09-01
  • Safari

    v15.4+
    2022-03-14
  • Safari (iOS)

    v15.4+
    2022-03-14
  • Firefox

    v121+
    2023-12-19

機能名やコードで検索できます

例:aspect-ratio、:has()、padding-top

別の言葉や、プロパティ名で試してください

検索を読み込めませんでした