
使える環境が整った:has()
CSSの疑似クラスの:has()ですが、Safariに続いて、ChromeやEdgeでも使えるようになり、ようやく環境が整ってきました。
:has() CSS relational pseudo-class
https://caniuse.com/css-has
とは言うものの、:has()の機能は「指定したセレクタに該当した要素がある場合にスタイルを適用できる」というものです。特定の要素(たとえば画像)の有無でスタイルを切り替えるといったサンプルで紹介されるケースが多く、確かに便利なんですが…。
次の記事で紹介されているような、フォームの選択に応じて追加項目を表示したり、アイテム数に応じてCSS Gridのレイアウトを調整するといった使い方に:has()の威力を感じます。CSSの外側(JavaScriptなど)で必要だった面倒な処理が、軽い処理で、もしくはCSSだけで済むようにようになる、といったものです。

CSSの外側まで考えると、:has()が非常に強力なことが見えてきます。そんなものの1つに、スクロールスパイがあります。
Scrollspy(スクロールスパイ)を考えてみる
コンテンツの表示に合わせてメニューの表示を更新し、現在アクティブなコンテンツを明示するものをScrollspy(スクロールスパイ)といいます。
QiitaやZennなどで表示されているTOC(目次)をイメージしてもらうのが良いかと思います。


Bootstrapにも用意されているのですが、思い通りの構造ではなく、結局自分で実装することになることも。
1階層のシンプルなものや、以下のような構成でも、アクティブなものだけにスタイルを当てるのであれば、それほど難しくはありません。
.menu li.active > a { background-color: LightSkyBlue;}

しかし、親にもスタイルを当てるとなると、なかなか面倒です。
:has()なしで親にスタイルを当てるならどうするか
色々とやり方はあるかと思いますが、たとえば、こんな感じで親の見えるデータを用意しておいて、それを参照しながらアクティブなものを変化させていくことになるでしょうか。
{ "スイーツ": [], "チョコ":["スイーツ"], "ミルク":["チョコ","スイーツ"], "ビター":["チョコ","スイーツ"], "ジャム":[], "苺":["ジャム"], "ぶどう":["ジャム"], "パン":[], "ハード系":["パン"], "バケット":["ハード系","パン"], "ソフト系":["パン"], "ドリンク":[]}
こうしたデータを作成するのも、大したことはないといえばそうなのですが、なかなか面倒です。そこで、:has()の出番です。
:has()を使って親にスタイルを当てる
たとえば、こんな感じのCSSを用意しておけば、親には勝手にスタイルが当たることになりますので、上のようなデータを用意する必要もありません。
.menu li.active > a { background-color: LightSkyBlue;}
.menu li:has(.active) > a { background-color: PaleTurquoise;}

さらに、アクティブなものと、その親、さらに、その親でスタイルを変えるなんてことも、非常にシンプルに実現できます。

コードパターンA
.activeなものに対して相対的に色を指定。
.menu li.active > a { background-color: LightSkyBlue;}
.menu li:has(> ul > .active) > a { background-color: PaleTurquoise;}
.menu li:has(> ul > li > ul > .active) > a { background-color: MidnightBlue; color: white;}
DEMO(Safari 15.4、Chrome 105、Edge 105以上が必要です):
コードパターンB
階層ごとに色を固定。
.menu > li.active > a,.menu > li:has(.active) > a { background-color: MidnightBlue; color: white;}
.menu > li li.active > a,.menu > li li:has(.active) > a { background-color: PaleTurquoise;}
.menu > li li li.active > a,.menu > li li li:has(.active) > a { background-color: LightSkyBlue;}
DEMO(Safari 15.4、Chrome 105、Edge 105以上が必要です):
CSSだけで考えると地味に見えますが、その外側の処理まで考えるとなかなか強力です。処理をブラウザに任せられますので。ただ、ブラウザに任せるためには、HTMLによるマークアップも意識しておく必要はあります。
IEを意識しなくて良くなったことで注目を浴びているモダンCSSですが、CSSだけで見るとピンと来ないものが結構あります。CSSの外側も含めて見直してみることをオススメします