1. web design shake
  2. コーディング
  3. 疑似クラス:has()で広がるCSSの可能性!使い方をコードで解説【全ブラウザ解禁】
疑似クラス:has()で広がるCSSの可能性!使い方をコードで解説【全ブラウザ解禁】

疑似クラス:has()で広がるCSSの可能性!使い方をコードで解説【全ブラウザ解禁】

当サイトは広告を使用しています。

朗報だにゃ!

ついにすべてのモダンブラウザで:has()疑似クラスが使えるようになりました。
これまではJSと組み合わせて判別していた「特定の子孫要素がある親要素」のスタイリングが、CSSだけで完結します。

この記事では疑似クラス:has()の書き方から、実際どんな時に使えるのかを実例付きでご紹介。どんな場面で使えるか頭に入れておくことで、これからのコーディングがグッと楽になりますよ!

:has()疑似クラスは、CSSセレクタの一種で、特定の条件を満たす子孫要素を持つ親要素を選択するために使います。従来のCSSだけでは難しかった「特定の子孫要素があれば親要素をスタイリングする」ことが可能になります。

:has()疑似クラスは親要素を特定の子孫要素があるかどうかに基づいてスタイリングできる

疑似クラスのおさらいはこちらからどうぞ!

長らく実験的な機能であった:has()ですが、2023年から全ての主要ブラウザでサポートされました。これからは迷いなく使うことができますよ!

:has()の基本的な構文は以下の通りです。
これで特定の子孫要素セレクタを持つ親要素に対し、スタイルを適用させることができます!

親要素セレクタ:has(子孫要素セレクタ) {
    /* スタイル */
}

簡単な例を見てみましょう。
以下の例ではspanを持つ、divに対し、スタイルを適用しています。

div:has(span) {
    color: red;
}

See the Pen has by web design shake (@webdesignshake) on CodePen.

今までにない指定の仕方が可能になりましたね!
子孫要素セレクタにより、その要素があるかないかを判定できるのということは、要するに条件分岐が可能になったということです。JSなしでこれはすごい!

CSSだけで条件分岐ができるから嬉しい!

また、:has()に+を記述し、後続兄弟セレクタを使うことで特定の要素が直後に続く要素に対してスタイルを適用できます。こちらも便利な機能で、直後に続く要素によってその前の要素のスタイルを変える、ということができるようになっています。

div:has(+span) {
    color: red;  /*直後にspanが続くdivにスタイルをあてる*/
}

See the Pen has1-1 by web design shake (@webdesignshake) on CodePen.

ここからはどういう場面で:has()を使うかを実例で紹介するにゃ!

それでは、:has()が実際にどんな場面で活躍するのか実例で見ていきましょう!

画像があるカードにはflexを追加する

カードレイアウトで、画像があるカードと、画像がないカードが混在している場面を想定しました。
こんなとき、「子要素に画像があるかどうかによって親要素のスタイルを分けたい!」と思うことがありますよね?
: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()を活用したアイデアがたくさん生まれてくる予感がします。

CATEGORY