【入門編】 has擬似クラスの実務デザインパターン – CSS実践ガイド

こんにちは!フロントエンドの現場を渡り歩いているチーフアーキテクトの私です。

CSSを書き始めたばかりの頃って、「あ、このボタン、中のテキストが空っぽのときは非表示にしたいな」「フォームの入力欄に文字が入ったら、まわりの枠線の色を変えたいな」なんて思ったとき、どうしていましたか?

「JavaScriptでクラスを付け外ししなきゃいけないのかな……」って、頭を抱えた経験、ありませんか? 実はそれ、もうJavaScriptの出番じゃありません。CSSのすごい味方、`:has()`(ハズ)擬似クラスを使えば、CSSだけでスマートに解決できちゃうんです!

今日は、この `:has()` のすごさと、現場で即戦力になる実用的なデザインパターンを、身近な例えを交えながら優しく紐解いていきますね。初心者の方も、「なるほど、そういうことか!」と膝を打っていただけるよう丁寧に解説しますので、どうぞリラックスして読んでいってください。

—

1. `:has()` ってどんな機能?(親を操る魔法のセレクタ)

これまでのCSSって、基本的には「上から下へ(親から子へ)」スタイルを流し込むことしか得意ではありませんでした。「こういう子どもが入っているときだけ、親の格好を変える」というのは、ちょっと苦手だったんです。

それを例えるなら、「お弁当箱の中に『梅干し』が入っているときだけ、お弁当箱の包み紙を赤色に変える」ようなもの。

昔のCSSだと、お弁当箱自体に「梅干し用だよ」という特別なクラス(目印)をわざわざ貼ってあげないと、包み紙の色を変えられませんでした。
でも、この `:has()` を使うと、「お弁当箱の中に梅干しが入っているか?」をCSS自身が中身を覗き込んでチェックし、条件に合えば自動的に親(お弁当箱)のスタイルを変えてくれるんです。

別名、「親セレクタ」とも呼ばれるこの機能、使いこなせるとCSSの世界がガラリと変わりますよ!

—

2. 実務で即効!`:has()` の基本デザインパターン3選

それでは、実際のWeb制作の現場で「これ、めちゃくちゃ助かる!」と感動する3つのパターンを、サンプルコード付きで見ていきましょう。

パターンA:フォームの入力欄が「空っぽかどうか」でおしゃれに変身させる

お問い合わせフォームを作っているとき、「あ、ここ未入力だな」とユーザーに優しく教えてあげたい場面、ありますよね。

`:has()` を使うと、「入力欄(input)に文字がフォーカスされている時」や「中身が入っている時」に、その大元のパーツ(wrapper)全体を光らせたり、枠線を変えたりすることが簡単にできます。


/ CSSのコード /

/ 通常の状態 /
.form-field {
border: 2px solid #ccc;
padding: 12px;
border-radius: 8px;
transition: all 0.3s ease;
}

/ ★ここがポイント!
「.form-field の中に、フォーカスされている input があるとき」という意味になります /
.form-field:has(input:focus) {
border-color: #3182ce; / 綺麗な青色にする /
box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.2); / ふわっと光らせる /
}

「親である `.form-field` が、子どもの状態を見て自ら変身する」。この直感的な気持ちよさ、伝わりますでしょうか?

—

パターンB:画像があるカードと、ないカードでレイアウトを自動で切り替える

ブログの一覧やニュース記事などで、「画像付きの記事」と「文字だけの記事」が混ざっているレイアウトを作ったことはありませんか?

「画像があるときは左右に並べて、文字だけのときは全幅に広げたい……」なんてとき、CSSだけでスマートに対応できます。

サムネイル

記事のタイトルが入ります

ここに本文の要約が入ります…

お知らせのタイトルです

画像がない場合はテキストを広く使いたい!

/ カードの基本の形(画像がないときは上下の積み上げレイアウト) /
.card {
display: flex;
flex-direction: column;
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
}

/ ★ここがポイント!
「もし、この card の中に img が『含まれている(has)』なら、横並び(row)に変えちゃおう!」 /
.card:has(img) {
flex-direction: row; / 横並びにする /
gap: 16px;
align-items: center;
}

/ 画像がある場合のスタイルの調整 /
.card:has(img) img {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 4px;
}

わざわざHTML側に `class=”card–has-image”` のようなクラスを追加しなくても、CSSが勝手に中身を判断してレイアウトを切り替えてくれるんです。メンテナンス性が劇的に上がりますよね。

—

パターンC:チェックボックスがONのときだけ、行全体の色を変える(リストの選択状態)

ToDoリストや、ショッピングカートの「商品選択チェックボックス」などでよくあるデザインです。チェックを入れた瞬間、その行全体が薄い青色に染まるアレです。

/ リスト項目のベース /
.todo-item {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
background: #fff;
border-bottom: 1px solid #eee;
cursor: pointer;
transition: background 0.2s;
}

/ ★ここがポイント!
「.todo-item の中に、チェックが入っている(input:checked)ものがあるなら」 /
.todo-item:has(input:checked) {
background: #edf2f7; / 背景をグレーっぽくする /
}

/ チェックが入ったテキストは取り消し線を引いて薄くする /
.todo-item:has(input:checked) .todo-text {
text-decoration: line-through;
color: #a0aec0;
}

「親(label全体)」にクラスがついていなくても、子どもの状態(`input:checked`)をトリガーにして親を染め上げる。これが `:has()` の真骨頂です。

—

3. 使ってみてつまずきやすいポイントと、温かいアドバイス

ここまで読んで、「すごい便利じゃん!早速明日から全部に使おう!」と思ったそこのあなた。ちょっと待ってくださいね。現場のプロとして、つまずきやすいポイントをそっとシェアしておきます。

1. 「あれ、効かない?」と思ったらブラウザのバージョンを確認
`:has()` は比較的新しい機能ですが、現在は主要なモダンブラウザ(Safari、Chrome、Edge、Firefox)すべてでしっかりとサポートされています。「数年前の古いブラウザ」をガチガチにサポートしなければならない案件でなければ、安心して使って大丈夫です!
2. あまりに複雑にネスト(入れ子)しすぎない
`:has(:has(:has(…)))` のように何重にも中身を覗き見するような書き方をすると、ブラウザが計算するのに疲れてしまい、ページの表示速度が遅くなる原因になります。「親のスタイルを変えるために、直下の子どもの状態を見る」くらいのスッキリした使い方を心がけましょう。

—

まとめ:CSSをもっと自由に、もっと楽しく!

いかがでしたでしょうか?
`:has()` 擬似クラスは、これまで「JavaScriptにお願いするしかなかったこと」を、そっとCSSの領域に連れ戻してくれた最高の機能です。

「親から子へ」だけでなく、「子どもの様子を見て、親が自分を変える」。この柔軟なアプローチが手に入ると、HTMLの構造を無駄に汚さず、シンプルで美しいコードが書けるようになります。

最初は少し難しく感じるかもしれませんが、まずは今回ご紹介した「フォームの入力欄」や「カードのデザイン」あたりから、自分のローカル環境でこっそり試してみてくださいね。

あなたが書くCSSが、もっと楽しく、もっと自由なものになりますように。現場のチーフアーキテクトより、応援しています!

コメント

タイトルとURLをコピーしました