
CSSは常に進化を続け、開発者に新たな表現力と効率性をもたらしています。その中でも、近年注目を集めているのが :has() 疑似クラス です。従来のCSSセレクタでは難しかった「特定の子要素を持つ親要素」を選択できるこの強力な機能は、モダンなWeb開発において無視できない存在となりつつあります。
本記事では、:has() の基本的な使い方から、より複雑なユースケース、そして実装における注意点までを、経験豊富な開発者の皆様に向けて詳細に解説します。
:has() 疑似クラスとは?
:has() は、ある要素が指定されたセレクタに一致する子要素を 含んでいるかどうか に基づいて、その要素自身を選択するための疑似クラスです。この特性により、従来のCSSでは不可能だった、より柔軟で直感的なスタイリングが可能になります。
基本的な構文は以下の通りです。CSS
親要素:has(子要素セレクタ) {
/* スタイル */
}
この構文は、「子要素セレクタ に一致する子要素を持つ 親要素 に対して、指定されたスタイルを適用する」と読み解けます。
例えば、以下のようなHTML構造があったとしましょう。HTML
<div class="card"> <img src="image.jpg" alt="Image"> <p>画像付きのカードです。</p> </div> <div class="card"> <p>テキストのみのカードです。</p> </div>
このとき、画像を持つ .card 要素にのみ特定のスタイルを適用したい場合、従来のCSSでは親要素の状態を直接的に判断する手段がなく、JavaScriptに頼ることが一般的でした。しかし、:has() を使用すれば、CSSのみでこれを実現できます。CSS
.card:has(img) {
border: 3px solid blue;
}
この一行のCSSで、「<img> 要素を子に持つ .card 要素」に対して青いボーダーを適用できます。
コード例で理解を深める:実践的なスタイリング
それでは、実際に提供いただいたコード例を用いて、:has() の具体的な動作を見ていきましょう。
HTML:HTML
<div class="card"> <img src="https://images.unsplash.com/photo-1583512603805-3cc6b41f3edb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxNTgwfDB8MXxzZWFyY2h8MTB8fGRvZ3xlbnwwfHx8fDE3NDI3OTcxOTB8MA&ixlib=rb-4.0.3&q=80&w=400" alt=""> </div> <div class="card"> <p>:has()のテストです。</p> </div>
CSS:CSS
img {
vertical-align: bottom;
}
.card:has(img) {
border: 3px solid blue;
margin-bottom: 20px;
}
.card:not(:has(img)) {
border: 1px solid red;
background-color: bisque;
}
このコードでは、.card クラスを持つ2つの div 要素があります。
- 最初の
divは<img>要素を子に持っています。 - 2番目の
divは<p>要素のみを子に持っています。
CSSのルールを見てみると、
.card:has(img)は、「子要素に<img>を持つ.card」に対して、青い3pxのボーダーと20pxの下マージンを適用しています。つまり、最初のdivがこのスタイルを受けます。.card:not(:has(img))は、「子要素に<img>を持たない.card」に対して、赤い1pxのボーダーとビスケット色の背景色を適用しています。つまり、2番目のdivがこのスタイルを受けます。
実際にこのコードがどのように動作するかは、以下のCodePenで確認できます。HTML
See the Pen Untitled by This is standard (@koutafunahashi) on CodePen.
このように、:has() を使うことで、HTMLの構造に基づいて、柔軟かつ動的にスタイルを適用できることがわかります。また、:not() 疑似クラスと組み合わせることで、「持たない場合」のスタイルも簡潔に記述できます。
:has() の多様な活用例:更なる可能性
:has() の真価は、より複雑なシナリオでこそ発揮されます。以下に、いくつかの活用例を紹介します。
フォームの入力状態に応じたスタイリング
例えば、必須入力フィールド (input[required]) を持つフォームにおいて、そのフィールドが空である場合に親要素のスタイルを変更することができます。
HTML
<form>
<div>
<label for="name">名前</label>
<input type="text" id="name" required>
</div>
<button type="submit">送信</button>
</form>
CSS
form:has(input[required]:placeholder-shown) {
border: 1px solid lightgray;
}
form:has(input[required]:not(:placeholder-shown)) {
border: 2px solid green;
}
この例では、必須入力フィールドがプレースホルダーを表示している(つまり、まだ入力されていない)場合、フォームのボーダーを薄いグレーに、何らかの入力がされた場合は緑色の太いボーダーに変化させ 1 ることができます。 1. github.com github.com
ナビゲーションメニューの高度な表現
サブメニュー (<ul>) を持つナビゲーションアイテム (<li>) に対して、特別なスタイルを適用することも可能です。HTML
<nav>
<ul>
<li><a href="#">ホーム</a></li>
<li>
<a href="#">製品</a>
<ul>
<li><a href="#">製品A</a></li>
<li><a href="#">製品B</a></li>
</ul>
</li>
<li><a href="#">サービス</a></li>
</ul>
</nav>
CSS
nav li:has(ul) > a {
font-weight: bold;
/* サブメニューを持つアイテムの<a>タグを太字にする */
}
nav li:has(ul):hover > ul {
display: block;
/* ホバー時にサブメニューを表示する */
}
このように、:has() を使うことで、より洗練されたナビゲーションメニューの表現が可能になります。
特定の属性を持つ要素の存在に基づいたスタイリング
:has() は、要素の存在だけでなく、特定の属性を持つ要素の存在も検知できます。HTML
<div class="notification"> <p>新しいメッセージがあります。</p> <span class="unread"></span> </div> <div class="notification"> <p>既読の通知です。</p> </div>
CSS
.notification:has(.unread) {
background-color: lightyellow;
border-left: 5px solid orange;
}
この例では、.unread クラスを持つ span 要素を含む .notification に対して、背景色と左のボーダーを適用しています。
:has() を使う上での注意点と今後の展望
:has() は非常に強力な機能ですが、利用する際にはいくつかの注意点があります。
パフォーマンスへの影響
:has() セレクタは、ブラウザがDOMツリーをより深く探索する必要があるため、複雑なセレクタを使用すると、パフォーマンスに影響を与える可能性があります。特に大規模なDOM構造を持つページでは、慎重な利用が求められます。
ブラウザの対応状況
:has() は比較的新しい機能であり、すべてのブラウザで完全にサポートされているわけではありません。現時点(2025年3月24日)では、主要なモダンブラウザ(Chrome, Firefox, Safari, Edge)の比較的新しいバージョンでサポートされていますが、古いブラウザや一部のモバイルブラウザでは利用できない可能性があります。プロダクション環境での利用を検討する際には、 Can I Use... などのサイトで最新のブラウザサポート状況を確認することが重要です。
セレクタの複雑性
:has() の内部に複雑なセレクタを記述すると、CSSの可読性やメンテナンス性が低下する可能性があります。適切な粒度でクラスを付与するなど、他のCSS設計原則と組み合わせて利用することが推奨されます。
今後の展望
:has() は、CSSの表現力を大きく向上させる可能性を秘めており、今後さらに多くのユースケースが発見されることが期待されます。コンポーネントベースのデザインや、より動的なUIの実現に貢献するでしょう。
まとめ
:has() 疑似クラスは、モダンCSSにおける強力な武器であり、これまでJavaScriptに頼らざるを得なかった多くのスタイリングの課題をCSSのみで解決できる可能性を秘めています。パフォーマンスやブラウザサポートに注意しながら、積極的に活用していくことで、より柔軟で効率的なWeb開発が実現できるでしょう。
ぜひ、あなたのプロジェクトでも :has() を活用し、新たなスタイリングの可能性を探ってみてください。