<div class="foo">
ここは青くしたい
<div class="bar">
ここは赤くしたい
</div>
</div>
.foo{
color:blue;
}
.foo .bar{
color:red;
}
その.foo .bar
どうにかならない?
これはまだ2段階だから見ただけでわかりますが、ちょっと複雑なことをやるとすぐ地獄みたいなセレクタ塊になることは全CSS書きがよく知っています。
それを解決するために様々な解決策が現れましたが、いずれも外部ライブラリが必須だったり不自然な命名を強要されたり解決策同士の互換がないせいで乗り換えが大変だったりと非常につらい状況です。
ということで先日2023/04/05にリリースされたChrome112で、ようやくCSS Nestingがサポートされました。
ゴミみたいなことばっかり率先してやるくせに、全CSS書きが待ち望んでいる機能の実装には時間がかかるのはどうしてなんですかね。
ブラウザの対応状況
Chrome / Edge
Chrome112以降で使用可能です。
あとエンジンが同じEdgeも同じく112で対応しています。
.foo{
color:blue;
.bar{
color:red;
}
}
やったね。
Safari
記事執筆時点ではまだ対応していません。
記事執筆時点の最新版であるSafari16.4の次のバージョン、16.5でサポートされる予定です。
Firefox
記事執筆時点ではまだ対応していません。
ProprityはP3であり、優先度は中程度です。
2023年以降実装はきちんと進んでいるようなので、もうしばらくしたら対応されるのではないでしょうか。
CSS Nestingの書式ざっくり紹介
CSS Nestingの書式はざっくり言うとSASSのネストですが、細かいところで色々と違いがあります。
たとえば入れ子は文字列始まりにすることができず、記号始まりである必要があります。
/* だめ */
div {
div {
color: red;
}
}
/* これはOK */
div {
& div {
color: red;
}
}
/* これと同じ */
div {
:is(div) {
color: red;
}
}
文字列で始まるとプロパティ等と区別がつかなくなる可能性があるからということで、あえて非対応にしているようです。
そのため、ネストのセレクタは必ず記号始まりになります。
現在ネスト始まりとして使用できる記号は& @ : . > ~ + # [ *
です。
今回の例で使った&
は親要素を表すダミーのセレクタであり、まあSASSの&
です。
ネスト内側のセレクタは、単に外側のセレクタに続けて書かれたものと解釈されます。
/* &以外のセレクタも使用可能 */
.foo{
color: blue;
+ .bar{ color: red; }
> .baz{ color: yellow; }
}
/* ↑と同じ */
.foo{ color: blue; }
.foo + .bar{ color: red; }
.foo > .baz{ color: yellow; }
/* &を後ろに使うこともできる */
.foo .bar {
.baz & { color: red; }
}
/* ↑と同じ */
.baz :is(.foo .bar) { color: red; }
/* 複雑な入れ子 */
.foo, .bar {
color: blue;
+ .baz, &.qux { color: red; }
}
/* ↑と同じ */
.foo, .bar { color: blue; }
:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux { color: red; }
/* &をくっつけると&になる */
.foo{
&.bar { color: red; }
}
/* ↑と同じ */
.foo.bar { color: red; }
/* ただし&の文字列結合はしない */
.foo {
color: blue;
&Bar { color: red; }
}
/* ↑と同じ */
.foo { color: blue; }
Bar.foo { color: red; }
/* SASSではこうなるが、CSS Nestingではならない */
.foo { color: blue; }
.fooBar { color: red; }
入れ子要素の詳細度は:is()
と同じになります。
article {
& { color: red; }
color: blue;
}
これはcolor: red
のほうが勝って、フォントカラーは赤になります。
&
は親セレクタの文字列そのままを表すので、こんなこともできます。
div{
& &{
color:blue;
}
& span & {
color:red;
}
}
/* ↑と同じ */
div div { color:blue; }
div span div { color:red; }
なんの意味があるかはよくわかりません。
メディアクエリやCSS関数などの既存要素と組み合わせることももちろん可能です。
.foo{
color: red;
@media screen and (min-width: 1000px) {
color: blue;
@media screen and (min-width: 2000px) {
color: yellow;
}
}
}
1000px以下なら赤、2000px以下なら青、それ以上は黄色になります。
便利といえば便利ですが、下手にこれまでの使い方と混ぜると今以上の地獄になりそうな気もしますね。
CSS Nestingにはこれ以外にも様々な利用法がありますが、正しくは公式ドキュメントを見てください。
日本語訳も見つけましたが、不自然さが散見されるので機械訳っぽくてこちらは微妙ですね。
その他
2021年に書かれたそろそろ Native CSS Nesting の話をしようで紹介されている@nest
の書式は削除されていました。
また&
を後ろにも書けるようになっているなど、当時から書式の変更も見られます。
こういった変更は公式にdiffで見れるようにしてほしいですね。
感想
これでようやく、ブラウザ単体でネストできるようになります。
とはいえユーザ全員がすぐに最新ブラウザを使うかというとそうでもないので、もうしばらくはトランスパイルが必要でしょう。
ちなみに今使っているブラウザがCSS nestingに対応しているかはここで確認可能です。
今後の予定
Chrome公式によると、ネストの記号始まり制限を外してほしいという要望がたくさん来ているらしく、もしかしたら今後記号始まり制限が外れるかもしれません。