TL;DR 仕様的に許可されていません
:has()
疑似クラスは他の:has()
の中に入れ子にすることはできません。
— https://developer.mozilla.org/ja/docs/Web/CSS/:has#構文
ただ、:has()
内の has
を削除するだけで凡そ簡単に解消できると思います。
背景と問題例
Web アプリの利用時に、普段は見えなくしておきたい要素が有り、
特定の要素をホバーしたりフォーカスしたりすると見えるようにする、ちょっとトリッキーなユーザースタイルを書いていました。
e.g. .my-header
内の hover、focus 時以外は .target
を非表示にする
body:has(.my-header:not(:hover)) {
&:has(.my-header:not(:has(:focus))) { /* has の入れ子あり */
.target {
&:not(:hover, :focus, :has(:focus)) { display: none }
}
}
}
hover だけだと .target の操作が出来なくなるので、.my-header 内のリンクやボタンなどインタラクティブな要素をドラッグ(focus)した状態でも消えない様にするハックを入れてます。
ただ上記のコードでは残念ながら、仕様のとおり意図したスタイルが適用されません。
解決策
:has()
を入れ子しない書き方に修正します。
例の場合では body:has(.my-header:not(:has(:focus)))
を body:not(:has(.my-header :focus))
とする事で解消できました。
body:has(.my-header:not(:hover)) {
&:not(:has(.my-header :focus)) { /* Fixed */
.target {
&:not(:hover, :focus, :has(:focus)) { display: none }
}
}
}
結果として CSS も多少シンプルになって読みやすくなりました。
仕様としてもその辺を見越しての物なのかなと思いました。
/* Before */
body:has(.my-header:not(:has(:focus))) {}
/* After */
body:not(:has(.my-header :focus)) {}
挙動の例は以下の JSFiddle で確認できます。
https://jsfiddle.net/4cj7xmo9/
https://jsfiddle.net/5yj1sa07/ (下記に関連する不要な行・コメント削除版)
:has()
を入れ子にしてしまうと後続のスタイルに悪影響が出てしまう様なので、
利用の際はその点だけご注意ください。
2024年11月26日時点でバグ?は解消している様です。
何にしても has の入れ子は無効な書き方なのでご注意ください。