CSS :has()セレクターで親要素を選択する方法

問題

CSSで「子要素の状態に応じて親のスタイルを変えたい」という要件がある場合、以前は必ずJavaScriptが必要でした。

checkbox.addEventListener('change', (e) => {
  e.target.closest('.card').classList.toggle('selected');
});

このような単純なスタイル変更にJavaScriptを使うのは、あまり理想的ではありません。

解決方法

:has()セレクターを使えば、CSSだけで実現できます。すべてのモダンブラウザで対応しています。

/* チェック済みのチェックボックスを持つカード */
.card:has(input:checked) {
  border-color: #3b82f6;
  background-color: #eff6ff;
}

/* 画像を含む投稿アイテム */
.post-item:has(img) {
  grid-template-columns: 200px 1fr;
}

/* 空の入力フィールドを持つフォームグループ */
.form-group:has(input:placeholder-shown) {
  opacity: 0.7;
}

より実用的な例もあります。

/* エラーメッセージが表示されたら入力フィールドのボーダーを赤に */
.field:has(.error-message:not(:empty)) input {
  border-color: #ef4444;
}

/* 動画を含むセクションはパディングなし */
section:has(video) {
  padding: 0;
}

ポイント

  • :has()はCSSで親要素・兄弟要素を条件付きで選択できるセレクターです
  • JavaScriptなしで、純粋なCSSだけで状態ベースのスタイリングが可能になりました
  • すべてのモダンブラウザで対応しています(Chrome 105+、Firefox 121+、Safari 15.4+)
  • 過度に複雑な:has()のチェーンはパフォーマンスに影響する可能性があるため、注意が必要です