【CSS】CSSの擬似クラス :has() の使い方

CSSの :has() 擬似クラスは、特定の要素が特定の子要素や内容を持っているかどうかを判断し、その親要素にスタイルを適用できるとても便利な機能です。今回は、この擬似クラスについてまとめていきたいと思います。

:has() とは?

:has() は「親要素が特定の子要素を持っている場合」に適用できる擬似クラスです。従来のCSSでは、親要素を子要素の状態に応じて変更することはできませんでしたが、:has() を使用することで可能になります。

CSS
div:has(img) {
  border: 2px solid blue;
}

上記の例では、<div> の中に <img> 要素が含まれている場合、その div に青い枠線が適用されます。

サンプルコード

論理演算

特定の要素の中にh2要素が含まれている場合は、背景色を変更してみます。

See the Pen Untitled by tones (@tonescodedesign) on CodePen.

HTML
<div class="columns">
  <div class=col>
    <h2>h2見出し</h2>
    <p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
  </div>
  
  <div class="col">
    <p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
  </div>
</div>
CSS
.columns {
  display: flex;
  gap: 30px;
}

.col {
  padding: 30px;
  color: #fff;
  background-color: #94b4ce;
}

.col:has(h2) {
  background-color: #82a694;
}

上記は、h2がある場合は「#82a694;」になるように設定しています。

次兄弟結合子

次は、h2の「margin-bottom」の数値を後に続く要素によって変更してみます。

例えば、h2の基本となるmargin-bottomを30pxとします。ただし、h2のすぐ後にh3要素が続く場合はh2のmargin-bottomを違う数値に変更したい、という場合は以下のように設定ができます。

See the Pen :has() by tones (@tonescodedesign) on CodePen.

CSS
h2 {
  margin: 0 0 30px;
}

h2:has(+ h3) {
  margin-bottom: 15px; /* h2の後にh3が続く場合は15px */
}

h3 {
  margin: 0 0 15px;
}

その他色々な使い方

CSS
/* spanタグを含むh2に対して */
h2:has(span) { ... }

/* figcaptionがあるfigure要素に対して */
figure:has(> figcaption) { ... }
 
/* figcaptionがないfigureに続くp要素に対して */
figure:not(:has(figcaption)) + p { ... }

/* 直下にa要素がない.containerに対して */
.container:not(:has(> a)) { ... }
 
/* 子要素の数が3つ以上の.containerに対して */
.container:has(> .container__item:nth-child(3)) { ... }

/* 子要素の数が偶数の.containerに対して */
.container:has(> .container__item:last-of-type:nth-of-type(even)) { ... }

このように:has() を活用することで、より柔軟なCSS設計が可能になります。

さいごに

:has() は親要素に適用されるため、影響範囲が広くなりやすいです。パフォーマンスを考慮し、できるだけ特定の要素に対して適用するようにしましょう。