引数に渡したセレクタにマッチする要素を含む要素を選択する :has() 疑似クラス

2022.05.05

MAD 事業部の高橋ゆうきです。

以前の記事で CSS の Cascade Layers について書きました。このときの Safari 15.4 のリリースによって :has() 疑似クラスも実装されているため、こちらについても整理してみます。

ただし Chrome では Canary であっても Experimental Web Platform features のフラグが有効化されている必要があります。

実際に使えるようになるのはもう少し先になりそうです。

このページの画面キャプチャについては Chrome Canary でフラグを有効化したときの表示となります(Chrome 101でもフラグを有効化することで確認可能です、確認後設定をもとに戻すことをわすれないように注意が必要ですが……)。

:has() 疑似クラス

CSS のセレクタは先祖にさかのぼることができませんでした。以下は動かないサンプルです。

/* < は機能しない */
ul < .item {
  background-color: pink;
}

/* subject indicator というのも提案されていたことがあります */
!ul > .item {
  background-color: pink;
}

:has() 疑似クラスはその問題を解決するものです。上記のように .item が親が ul の場合に、 ul の背景色を変更したい場合には以下のように記述します。

ul:has(.item) {
  background-color: pink;
}

ul {
  background-color: orange;
}

has擬似クラスで背景色が変化している様子

jQyery の :has() Selector と同じなので、親しみがある構文だと感じる人も多そうです。

@support でサポートしているブラウザにのみ適用させる

@supports selector(:has(a)) {
  ul:has(.item) {
    background-color: pink;
  }
}

@support でサポートしているブラウザにのみ適用させることもできます。

:where 擬似クラスで詳細度を調整する

上記の ul:has(.item) の詳細度は (0, 1, 1) となります。詳細度を上げたくない場合には :where 擬似クラスと併用します。

ul:where(:has(.item)) {
  background-color: pink;
}

ul {
  background-color: orange;
}

:whereで詳細度を調節する

ul:where(:has(.item)) の詳細度は (0, 0, 1) となります。場合によっては Cascade Layers を使うこともできそうです。

まとめ

Safari にのみ実装された機能であるため、実際に同様のことをしたい場合には JavaScript に頼らざるを得ません。:has 擬似クラスが使えるようになると、一部のそのようなスタイルのための条件分岐を CSS のみで完結できるため、すべてのブラウザで使用できる日が来るのが待ち遠しい機能の 1 つです。

ただし、大きいスコープで引数の要素が絞りきれていないような使い方は少し危ないかもしれません。

.foo:has(a) {
  color: blue;
}

上記は極端な例になってしまいますが、これだと意図していない場合にも文字色が変わってしてしまうことがありそうです。

参考