Skip to content

Commit

Permalink
Chrome 130でのCSSネスティング改善: CSSNestedDeclarationsの詳細 (#52)
Browse files Browse the repository at this point in the history
* update

* update

* update

* update
  • Loading branch information
Yuto Yoshino authored Oct 14, 2024
1 parent b47161b commit 56549fa
Showing 1 changed file with 131 additions and 0 deletions.
131 changes: 131 additions & 0 deletions app/routes/posts/css-nesting-improves-with-cssnesteddeclarations.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
title: "Chrome 130でのCSSネスティング改善: CSSNestedDeclarationsの詳細"
description: "web.devが先日、CSS nesting improves with CSSNestedDeclarationsというブログを公開しました。このブログでは、CSSネスティングの仕様にCSSNestedDeclarationsが追加されたことについて書かれています。導入背景やCSSOMの動きなどが少し面白かったのでブログにまとめました。"
date: "2024/10/13"
published: true
---

## Intro

[web.dev](https://web.dev/?hl=en)が先日、[CSS nesting improves with CSSNestedDeclarations](https://web.dev/blog/css-nesting-cssnesteddeclarations?hl=en)というブログを公開しました。

このブログでは、CSSネスティングの仕様に`CSSNestedDeclarations`が追加されたことについて書かれています。果たして業務でこのブログで書かれてるバグに出くわすことはなかった気もしますが、CSSOMの動きなど少し面白かったので書くことにしました。

## 話さないこと

この記事では以下の内容については書きません。

- CSS nestingとは
- CSSのparse処理について

## CSSネスティングでの既存のバグ

まず既存のCSSネスティングであったバグについてです。
以下のようなCSSを書いた場合、皆さんはどのようなUIになると思いますか??

```css
.foo {
width: fit-content;

@media screen and (min-width: 900px) {
background-color: red;
}

background-color: green;
}
```

関連: [github.com/yossydev/css-nesting-improves-with-cssnesteddeclarations](https://github.com/yossydev/css-nesting-improves-with-cssnesteddeclarations)

この場合、適用されるbackground-colorはred🛑になります。

<img src="https://github.com/user-attachments/assets/d2c31c61-c0fc-4584-a26f-ae813863db64"/>

(左: Chrome129 / 右: Chrome130)

しかし、CSSの仕様としては後ろに書かれたコードが適用されるはずです。これがChrome 129までのCSSネスティングに関するバグでした。

## なぜこのようなバグが存在するのか

なぜこのようなバグが存在していたのでしょうか?
それは、CSSOMを使ったパース処理が関係しています。

先ほどのCSSに対して生成されたCSSOMをみてみましょう。

```
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = ".foo"
.resolvedSelectorText = ".foo"
.specificity = (0,1,0)
.style (CSSStyleDeclaration, 2) =
- width: fit-content
- background-color: green
.cssRules (CSSRuleList, 1) =
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = "&"
.resolvedSelectorText = ":is(.foo)"
.specificity = (0,1,0)
.style (CSSStyleDeclaration, 1) =
- background-color: red
```

`background-color: green`は`CSSStyleRule.style`に含まれているものの、`@media screen`の後に定義されたかどうかはわからないです。そのため、パースされたCSSをみると、以下のようになります。(出力された結果から見やすくなるように少し整形しています)

```
.foo {
width: fit-content;
background-color: green;

@media screen and (min-width: 900px) {
background-color: red;
}
}
```

この結果、`background-color: green`が`@media screen`よりも上に来てしまいました。これではCSSの優先順位的に、`min-width: 900px`が正の時はredが適用されます。

(そもそも常に`background-color: green`にしたいなら`background-color: red`いらないのでは?みたいなご意見はごもっともです)

## CSSNestedDeclarationsの追加

先ほどの問題を解消するために、CSS Working Groupは新しく[nested declarations rule](https://drafts.csswg.org/css-nesting/#nested-declarations-rule)を追加しました。

同じCSSの内容に対して、Chrome130からは以下のようなデータ構造になります。

```
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = ".foo"
.resolvedSelectorText = ".foo"
.specificity = (0,1,0)
.style (CSSStyleDeclaration, 1) =
- width: fit-content
.cssRules (CSSRuleList, 2) =
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSNestedDeclarations
.style (CSSStyleDeclaration, 1) =
- background-color: red
↳ CSSNestedDeclarations
.style (CSSStyleDeclaration, 1) =
- background-color: green
```

今度は`CSSNestedDeclarations`というものが追加されているのがわかるかと思います。
これにより、パーサーは以前の宣言の位置を維持させることができるようになりました。

## まとめ

今回はChrome130で追加される`CSSNestedDeclarations`について、導入背景と一緒に見ていきました。
CSSのパースについて、正直今まで考えて開発をしてこなかったので、今回の内容で興味を持つきっかけになりました。特に今回はあまり触れられていないのですが、[nested declarations rule](https://drafts.csswg.org/css-nesting/#nested-declarations-rule)の具体的な実装内容みたいなところも、時間があれば読んでみたいと思います。

## 参考・関連

- [CSS nesting improves with CSSNestedDeclarations](https://web.dev/blog/css-nesting-cssnesteddeclarations?hl=en)
- [nested declarations rule](https://drafts.csswg.org/css-nesting/#nested-declarations-rule)

0 comments on commit 56549fa

Please sign in to comment.