この記事には広告を含む場合があります。
記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。
「チェックを入れたら、その項目だけ色が変わる」
「入力がそろったら、送信ボタンが押せる見た目になる」
こういう動きは、少し前まで JavaScript を書かないと作れませんでした。
それが今は、CSS の :has() を使うだけで、コピペで実現できます。
この記事では、:has() がどういうものかを、たとえ話と動くサンプルでやさしく説明します。
そのままコピペで使える実例と、WordPressでの使いどころ、つまずきやすい注意点までまとめているので、はじめての方でも順番に読めば使えるようになります。
:has()とは?ひとことで言うと
:has() は、中に何かを含んでいる「入れ物」のほうを選べるCSSです。
今までのCSSは、親から子へ、という一方向にしか効きませんでした。
親が中の子を装飾することはできても、中身を見て入れ物自身が変わることはできなかったんです。
イメージ
イメージはお弁当箱です。
今までのCSSは、箱の中のごはんや卵焼きを、ひとつずつ飾ることしかできませんでした。
でも :has() を使うと、「卵焼きが入っているお弁当箱」というふうに、中身を見て箱そのものを飾れます。
この「入れ物」は、専門用語だと親要素と呼びます。
名前は後で覚えれば十分なので、まずは「中身を見て、外側の入れ物を選べる」とだけ掴んでおけばバッチリです。
こんなときに :has() を使うと便利
:has() を使うかどうか迷ったときの、合言葉があります。
「中身がこうなったら、入れ物の見た目をこうしたい」。そう思った瞬間が、:has() の出番です。
たとえば、こういう場面が当てはまります。
- 選んだものを目立たせたいとき。チェックした項目や、選んだプランのカードを強調する。
- 入力の進み具合に反応したいとき。必須がそろったら、送信ボタンを押せる見た目にする。
- 中身のあるなしで分けたいとき。画像がある記事だけ、レイアウトを変える。
- 離れた場所を連動させたいとき。メニューを開いたら、ページ全体を暗くする。
これらはどれも、少し前まで JavaScript を書かないと作れませんでした。
状態を見張って、条件に合わせてクラスを付けかえて、そのクラスで見た目を変える。
この手間を、:has() がまるごと肩代わりしてくれます。
だから「中身に合わせて、外側を変えたいな」と思ったら、:has() を思い出してください。
ここで挙げた4つは、このあとの実例でひとつずつ、動くサンプルとコードで見ていきます。
基本の書き方
書き方はとても簡単です。
入れ物のセレクタのうしろに、:has() をつけて、カッコの中に「含んでいてほしい中身」を書きます。
たとえば「中に画像を含んでいる記事」なら、次のように書きます。
/* 中に img を含んでいる .card を選ぶ */
.card:has(img) {
/* ここに見た目の指定を書く */
}コツは、土台は素の状態で作っておいて、条件に合うものだけ上書きすることです。
どういうことか
まず全部に共通のデザインを当てておき、:has() で「中身がこうなっているものだけ」あとから足す。
この順番で書くと、ぐっと分かりやすくなります。
さきほどの .card:has(img) を、この順番で組み立ててみます。
まずは、画像のあるなしに関わらず、すべてのカードに共通の見た目を当てます。
これが土台です。
/* 土台 = すべてのカードに共通の見た目 */
.card {
border-left: 5px solid #37a845;
border-radius: 12px;
padding: 16px;
}この時点では、どのカードも同じ、文字主体の見た目です。
そのうえで、:has(img) を使って、画像を含むカードだけをあとから上書きします。
/* 画像を含むカードだけ、あとから上書き */
.card:has(img) {
padding: 0;
}① 土台だけ(.card)
② + :has(img) を足すと
変えたいのは余白だけなので、:has() の側はたった1行です。
土台をきちんと作っておくと、あとから足すルールは「変えたいところだけ」で済みます。
この「土台 → :has() で上書き」という骨組みは、このあとの実例でもくり返し出てきます。
コピペで使える実例
ここからが本題です。
実際に動くサンプルと、そのままコピペで使えるコードを4つ紹介します。
まずサンプルを触ってみて、下のコードと見比べるのが理解の近道です。
1. 選んだ項目だけ、まわりごと強調する
チェックを入れると、その項目全体の色が変わります。
チェックボックスではなく、それを囲っている項目のほうを狙っているのがポイントです。
/* チェック済みのチェックボックスを含む項目を強調する */
.item:has(input:checked) {
border-color: #37a845;
background: #f6faf6;
font-weight: 600;
}解説
はじめて見ると少し難しそうですが、パーツに分けて読むと簡単です。
.item:has(input:checked) は、「チェックが入ったinputを中に含んでいる .item」という意味です。
3つのパーツに分けると、こう読めます。
- .item … デザインを変えたい入れ物(ここでは項目)
- :has( ) … カッコの中を「中に含んでいる」という条件
- input:checked … チェックが入っている入力部品
つまり狙っているのは、チェックボックスそのものではなく、それを含んでいる項目のほうです。
プラン選択で「選ばれたカードだけ枠を強調する」といった使い方も、まったく同じ考え方でできます。
2. 入力がそろうと、送信ボタンが押せる見た目になる
名前とメールを両方うめると、グレーだった送信ボタンが緑に変わります。
「中に、空っぽの必須欄をひとつでも含んでいるフォーム」を見て、その間はボタンを押せなさそうに見せています。
/* 空の必須欄を含む間は、送信ボタンをグレーに */
.form:has(input:placeholder-shown) .submit {
background: #c3c9c3;
cursor: not-allowed;
}空かどうかは、プレースホルダー(うすい見本の文字)が見えているかどうかで判定しています。
ひとつ大事な注意があります。
これは押せなさそうに見せているだけで、本当にボタンを押せなくしているわけではありません。
本当に無効にしたい場合は、HTMLやJavaScriptの出番になります。
3. アイキャッチがある記事だけ、レイアウトを変える
ここからはWordPressで一番使いたくなる場面です。
同じ記事カードでも、アイキャッチ画像がある記事は画像を大きく、ない記事は左にラインを引いた文字主体に、自動で切り替わります。
コピペで使えるボタンデザイン20選
そのまま貼れるボタンを集めました。
register_block_style() で独自スタイルを足す
画像がない記事でも、ラインとタイトルで見出しが立ちます。
/* 土台 = 画像がない記事(文字主体) */
.card {
border-left: 5px solid #37a845;
padding: 16px;
}
/* 中に画像を含む記事だけ、画像主体に上書き */
.card:has(img) {
padding: 0;
}WordPressのアイキャッチは、表示されるとき多くの場合 img として出力されます。
だから :has(img) は、画像が入っているかどうかを直接見て狙えます。
テーマが「画像あり用のクラス」を用意してくれているかに頼らず、追加CSSだけで完結するのが便利なところです。
4. メニューを開くと、ページ全体を暗くする
これが、:has() で一番JavaScriptっぽいことができる例です。
左上のボタンを押すとメニューが出て、後ろのページ全体がふわっと暗くなります。
暗いところを押せば閉じます。
<div class="site">
<!-- 状態を覚える、見えないチェックボックス -->
<input type="checkbox" id="menu" class="toggle">
<!-- ハンバーガーボタン。押すと上のチェックが切りかわる -->
<label for="menu" class="burger">☰</label>
<div class="overlay"></div>
<nav class="drawer">…メニュー…</nav>
</div>/* 状態を覚える見えないチェックボックスは、隠しておく */
.toggle {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
/* ページ全体が、開いているトグルを含んでいるかを見る */
.site:has(.toggle:checked) .overlay {
opacity: 1; /* 暗くする */
}
.site:has(.toggle:checked) .drawer {
transform: none; /* メニューを出す */
}解説
このセレクタは、スペースで2つに分かれているのがポイントです。
スペースの前が「条件」、うしろが「実際に変える相手」です。
- .site:has(.toggle:checked) … 開いているトグルを含んでいる .site(=メニューが開いている状態)
- (スペース) … 「その中の」という意味
- .overlay … 実際に見た目を変えたい部品
つまり「メニューが開いている .site の中にある .overlay」を狙っている、ということです。
これまでの実例は、条件に合った入れ物そのものの見た目を変えていました。
今回は少し違って、条件は入れ物で見ますが、実際に変えるのは中の別の部品です。
だから :has() のうしろにスペースを空けて、変えたい相手を書いています。
2行あるのは、同じ「メニューが開いている」という条件で、暗くする幕(.overlay)と、出てくるメニュー(.drawer)の2つを動かしたいからです。
条件の部分は同じで、うしろの相手だけが違います。
暗くする指示を出しているのは、ページの一番外側の入れ物です。
メニューの開閉という小さなスイッチの状態を、ページ全体という大きな入れ物が受け取って、幕を出しています。
小さな一点の状態を、離れた場所の大きな見た目に伝える。
これがまさに、今までJavaScriptがやっていた連動の動きです。
なお、CSSは状態を記憶できないので、開いているか閉じているかを見えないチェックボックスに覚えさせています。
どういうことか
なぜ見えないチェックボックスが出てくるのか、ここも補足しておきます。
CSSには、状態を覚えておく機能がありません。
「今メニューが開いているか」を、CSS自身が記憶しておくことはできないんです。
CSSにできるのは、今のHTMLの状態を見て、それに合わせて見た目を決めることだけです。
そこで、状態を覚えておく役目を、チェックボックスにお願いします。
チェックボックスは、チェックが入っているか・いないか、という2つの状態をHTML側で覚えていられます。
これを「開いている・閉じている」の代わりに使うわけです。
ただ、画面にチェックボックスが見えていると邪魔なので、見た目だけ隠しています。
隠しても機能は生きていて、ハンバーガーボタンはこのチェックボックスを切り替えるスイッチになっています。
だからボタンを押すとチェックが切りかわり、その状態を :has(.toggle:checked) が読み取って、メニューを開いたり閉じたりできる、という仕組みです。
状態は本物のフォーム部品に持たせる、というのが :has() で連動を作るときの定番です。
WordPressで使うときのポイント
:has() は、WordPressでも普通に使えます。
ただのCSSなので、外観 → カスタマイズ → 追加CSS に書けば、そのまま効きます。
特に相性がいいのが、さきほどのアイキャッチの例です。
WordPressのアイキャッチは img として出力されるので、:has(img) で画像の有無を直接拾えます。
テーマの作りに左右されず、追加CSSだけで見た目を出し分けられるのが強みです。
ほかにも、特定のブロックを含むときだけ余白を足す、といった調整も、PHPを触らずにCSSだけでできます。
使う前に知っておきたい注意点
便利な :has() ですが、はじめに知っておくと安心なポイントがいくつかあります。
ひとつめは、変えられるのは見た目だけということです。
さきほどの送信ボタンのように、押せなさそうに見せることはできても、本当に押せなくする・入力を計算する・データを保存するといった処理はできません。
そこはJavaScriptの仕事のままです。
見た目の切り替えはCSSの :has()、実際の処理はJavaScript、という分担で覚えておくとバッチリです。
ふたつめは、:has() の中に :has() を入れることはできない、という点です。
条件を重ねたいときは、カッコの中でカンマ区切りにするなど、別の書き方でまとめます。
みっつめは、古いブラウザへの備えです。
:has() はChrome、Edge、Firefox、Safariの主要ブラウザで対応済みなので、今はそのまま使って問題ありません。
大事なのは、土台のデザインを :has() なしでも成立する形で作っておくことです。
そうしておけば、万一 :has() が効かない環境でも、崩れることなく、ただ強調が乗らないだけで済みます。
かなり古い環境からのアクセスが多いサイトだけ、@supports で囲んで対応ブラウザだけに適用する、という手もあります。
よくある質問
- :has() ってひとことで言うと何ですか?
- 中身を見て、外側の入れ物(親要素)のほうを選べるCSSです。
「チェックが入っている項目」「画像を含むカード」のように、中身を条件にして入れ物のデザインを変えられます。
- 何が便利なんですか?JavaScriptの代わりになりますか?
- 状態や中身に合わせた見た目の切り替えを、CSSだけで肩代わりできます。
今までJavaScriptが必要だった動きを、CSSで実現できるのが大きな利点です。
ただし、本当に押せなくする・処理を止めるといった動作の制御はできないので、そこはJavaScriptが必要です。
- WordPressでも使えますか?
- 使えます。
外観 → カスタマイズ → 追加CSS に書けば、そのまま効きます。
アイキャッチは img として出力されるので、:has(img) で画像の有無を拾って見た目を出し分けられます。
- 古いブラウザでも大丈夫ですか?
- 主要ブラウザはすべて対応済みです。
土台のデザインを :has() なしでも成立する形で作っておけば、万一効かない環境でも崩れず、強調が乗らないだけで済みます。
- :has() の中に :has() は書けますか?
- 書けません。
条件を重ねたいときは、カッコの中をカンマ区切りにするなど、別の書き方でまとめます。
- 送信ボタンは本当に押せなくなりますか?
- いいえ、押せなさそうに見せているだけです。
本当に無効化したい場合は、HTMLの属性やJavaScriptが必要です。
まとめ
:has() は、中身を見て入れ物のほうを選べる、はじめての「親を選べる」CSSです。
今までJavaScriptが必要だった見た目の切り替えが、コピペのCSSでできるようになりました。
選んだものを強調する、入力に反応する、中身のあるなしで分ける、離れた場所を連動させる。
どれも「中身がこうなったら、入れ物をこうしたい」と思ったときが出番です。
最後にもう一度だけ。
見た目はCSSの :has()、実際の動作はJavaScript。
この分担さえ押さえておけば、安心して使いこなせます。
それではノ

