ついにすべてのモダンブラウザで:has()疑似クラスが使えるようになりました。
これまではJSと組み合わせて判別していた「特定の子孫要素がある親要素」のスタイリングが、CSSだけで完結します。
この記事では疑似クラス:has()の書き方から、実際どんな時に使えるのかを実例付きでご紹介。どんな場面で使えるか頭に入れておくことで、これからのコーディングがグッと楽になりますよ!
疑似クラス:has()の基本について
:has()は親要素が特定の子孫要素を持つ場合のスタイリングに使える!
:has()疑似クラスは、CSSセレクタの一種で、特定の条件を満たす子孫要素を持つ親要素を選択するために使います。従来のCSSだけでは難しかった「特定の子孫要素があれば親要素をスタイリングする」ことが可能になります。
全ブラウザ対応解禁。もう使っても大丈夫!
長らく実験的な機能であった:has()ですが、2023年から全ての主要ブラウザでサポートされました。これからは迷いなく使うことができますよ!
疑似クラス:has()の書き方
特定の子要素を持つ親要素を指定する
:has()の基本的な構文は以下の通りです。
これで特定の子孫要素セレクタを持つ親要素に対し、スタイルを適用させることができます!
親要素セレクタ:has(子孫要素セレクタ) {
/* スタイル */
}
簡単な例を見てみましょう。
以下の例ではspan
を持つ、div
に対し、スタイルを適用しています。
div:has(span) {
color: red;
}
See the Pen has by web design shake (@webdesignshake) on CodePen.
今までにない指定の仕方が可能になりましたね!
子孫要素セレクタにより、その要素があるかないかを判定できるのということは、要するに条件分岐が可能になったということです。JSなしでこれはすごい!
特定の要素の直前の要素を指定する
また、:has()に+
を記述し、後続兄弟セレクタを使うことで特定の要素が直後に続く要素に対してスタイルを適用できます。こちらも便利な機能で、直後に続く要素によってその前の要素のスタイルを変える、ということができるようになっています。
div:has(+span) {
color: red; /*直後にspanが続くdivにスタイルをあてる*/
}
See the Pen has1-1 by web design shake (@webdesignshake) on CodePen.
どんな時に使うの?実例で:has()のメリットを実感しよう
それでは、:has()が実際にどんな場面で活躍するのか実例で見ていきましょう!
カード内に画像が含まれる場合のスタイル変更
カードレイアウトで、画像があるカードと、画像がないカードが混在している場面を想定しました。
こんなとき、「子要素に画像があるかどうかによって親要素のスタイルを分けたい!」と思うことがありますよね?
:has()を使うことでそれが可能になります。この例では画像がある場合にdisplay:flex;
を適用し、横並びにしています。
.card:has(img) {
display: flex; /* 画像があるのでflex追加 */
}
See the Pen has by web design shake (@webdesignshake) on CodePen.
フォーム要素が特定の状態の時のスタイル変更
:has()疑似クラスを利用することで、フォーム内の特定の要素が特定の状態(例えば無効または未入力)にある時に、フォーム全体や特定の部分のスタイルを変更することができます。
この例ではメールアドレスを入力するinput
欄を考えてみましょう。input
要素はtype="email"
を指定しているので、〇〇〇〇@〇〇〇〇というメールアドレス形式で文字を入力した場合はOKですが、それ以外の形式で入力されるとエラーメッセージが出るようになっています。
子要素であるinput
の状態によって、親要素であるform
の疑似要素:after
に対してスタイルの出し分けができています!
form:has(input:invalid:not(:placeholder-shown)):after {
display: block; /* 入力が正しくなければエラーメッセージ表示 */
animation: shake 0.3s;
}
form:has(input:focus:invalid:not(:placeholder-shown)):after {
display: none; /* フォーカス中はエラーメッセージを非表示 */
}
See the Pen has3 by web design shake (@webdesignshake) on CodePen.
:invalid(入力した形式が間違っている状態)や、:placeholder-shown(プレースホルダが表示されている状態)、:focus(入力中の状態)など、inputは疑似クラスによって入力状態のスタイルを出し分けることができます。今回の:has()はその応用で、それぞれの場合に応じてformの:after疑似要素の表示/非表示を切り替えるというものでした。
離れた場所にある要素へアクセスする
子孫要素→親要素→別の子孫要素と、:has()を使うことで離れた要素へスタイルを適用することができます。JSの制御なしにできるのが便利です。
この例ではトグルの切り替えによって離れた個所にある要素のスタイルを制御しています。トグルと、ON/OFFの文字列を表示させている部分は要素的に離れた個所にありますが、親要素である.container
に:has()を用いて経由させることでスタイルを適用させることができています。
.toggle:after { /* トグルOFF */
left: 0;
}
.toggle:has(input:checked):after { /* トグルON */
left: 70px;
background: #73feab;
}
.state:before { /* トグルOFF */
content:"OFF";
}
.container:has(input:checked) .state:before { /* トグルON .containerを介して別の子要素にスタイル適用 */
content:"ON";
color: #73feab;
}
See the Pen has4 by web design shake (@webdesignshake) on CodePen.
まとめ
いかがでしたか?
:has()疑似クラスの登場によって、親→子ではなく、親←子のようなセレクタ指定が可能となりました。今までは不可能だった方向のセレクタ指定が可能になったことで、よりコーディングが便利になりましたね。今後も:has()を活用したアイデアがたくさん生まれてくる予感がします。