【CSS】素のCSSでようやくネストができるようになった

```html:HTML
<div class="foo">
  ここは青くしたい
  <div class="bar">
    ここは赤くしたい
  </div>
</div>
```

```css:CSS
.foo{
  color:blue;
}

.foo .bar{
  color:red;
}
```

その`.foo .bar`どうにかならない？
これはまだ2段階だから見ただけでわかりますが、ちょっと複雑なことをやるとすぐ地獄みたいなセレクタ塊になることは全CSS書きがよく知っています。
それを解決するために様々な解決策が現れましたが、いずれも外部ライブラリが必須だったり不自然な命名を強要されたり解決策同士の互換がないせいで乗り換えが大変だったりと非常につらい状況です。


ということで先日2023/04/05にリリースされた[Chrome112](https://developer.chrome.com/articles/css-nesting/)で、ようやく[CSS Nesting](https://www.w3.org/TR/css-nesting/)が[サポート](https://caniuse.com/css-nesting)されました。
[ゴミみたいなことばっかり率先してやる](https://qiita.com/rana_kualu/items/19b141446b3f15b19dba)くせに、全CSS書きが待ち望んでいる機能の実装には時間がかかるのはどうしてなんですかね。


# ブラウザの対応状況

## Chrome / Edge

Chrome112以降で使用可能です。
あとエンジンが同じEdgeも同じく112で対応しています。

```css:CSS
.foo{
  color:blue;
  .bar{
    color:red;
  }
}
```

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/c8bc2923-38e8-2ea6-d7e3-1f5821f03257.png)

やったね。


## Safari

記事執筆時点ではまだ対応していません。
記事執筆時点の最新版であるSafari16.4の次のバージョン、[16.5でサポートされる予定](https://developer.apple.com/documentation/safari-release-notes/safari-16_5-release-notes)です。


## Firefox

記事執筆時点ではまだ対応していません。

[ProprityはP3](https://bugzilla.mozilla.org/show_bug.cgi?id=1648037)であり、優先度は中程度です。
2023年以降[実装はきちんと](https://hg.mozilla.org/mozilla-central/rev/aa5d7296f70a)[進んでいる](https://hg.mozilla.org/mozilla-central/rev/295ccc005c4f)ようなので、もうしばらくしたら対応されるのではないでしょうか。


# [CSS Nesting](https://www.w3.org/TR/css-nesting/)の書式ざっくり紹介

CSS Nestingの書式はざっくり言うとSASSのネストですが、細かいところで色々と違いがあります。
たとえば入れ子は文字列始まりにすることができず、[記号始まりである必要があります](https://developer.chrome.com/articles/css-nesting/#understanding-the-nesting-parser)。

```css:CSS
/* だめ */
div {
  div {
    color: red;
  }
}

/* これはOK */
div {
  & div {
    color: red;
  }
}

/* これと同じ */
div {
  :is(div) {
    color: red;
  }
}
```

文字列で始まるとプロパティ等と区別がつかなくなる可能性があるからということで、あえて非対応にしているようです。
そのため、ネストのセレクタは必ず記号始まりになります。
現在[ネスト始まりとして使用できる記号](https://developer.chrome.com/articles/css-nesting/#understanding-the-nesting-parser)は`& @ : . > ~ + # [ *`です。

今回の例で使った`&`は親要素を表すダミーのセレクタであり、まあSASSの`&`です。

ネスト内側のセレクタは、単に外側のセレクタに続けて書かれたものと解釈されます。

```css:CSS
/* &以外のセレクタも使用可能 */
.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()`と同じになります。

```css:CSS
article {
  & { color: red; }
  color: blue;
}
```

これは`color: red`のほうが勝って、フォントカラーは赤になります。


`&`は親セレクタの文字列そのままを表すので、こんなこともできます。

```css:CSS
div{
  & &{
    color:blue;
  }
  & span & {
    color:red;
  }
}

/* ↑と同じ */
div div { color:blue; }
div span div { color:red; }
```

なんの意味があるかはよくわかりません。

メディアクエリやCSS関数などの既存要素と組み合わせることももちろん可能です。

```css:CSS
.foo{
  color: red;
  @media screen and (min-width: 1000px) {
    color: blue;
    @media screen and (min-width: 2000px) {
      color: yellow;
    }
  }
}
```

1000px以下なら赤、2000px以下なら青、それ以上は黄色になります。
便利といえば便利ですが、下手にこれまでの使い方と混ぜると今以上の地獄になりそうな気もしますね。

CSS Nestingにはこれ以外にも様々な利用法がありますが、正しくは[公式ドキュメント](https://www.w3.org/TR/css-nesting/)を見てください。
[日本語訳も見つけました](https://triple-underscore.github.io/css-nesting-ja.html)が、不自然さが散見されるので機械訳っぽくてこちらは微妙ですね。


# その他

2021年に書かれた[そろそろ Native CSS Nesting の話をしよう](https://qiita.com/otsuky/items/68a5fa533aff3f9386e5)で紹介されている`@nest`の書式は削除されていました。
また`&`を後ろにも書けるようになっているなど、当時から書式の変更も見られます。
こういった変更は公式にdiffで見れるようにしてほしいですね。


# 感想

これでようやく、ブラウザ単体でネストできるようになります。
とはいえユーザ全員がすぐに最新ブラウザを使うかというとそうでもないので、もうしばらくはトランスパイルが必要でしょう。

ちなみに今使っているブラウザがCSS nestingに対応しているかは[ここで確認可能です](https://codepen.io/bramus/pen/oNdrypM)。


# 今後の予定

[Chrome公式](https://developer.chrome.com/articles/css-nesting/#the-future)によると、ネストの記号始まり制限を外してほしいという要望がたくさん来ているらしく、もしかしたら今後記号始まり制限が外れるかもしれません。