CSS の Cascade Layers を触ってみた

Chromium Blog: Chrome 99: CSS Cascade Layers, a New Picker for Input Elements, and More

CSSCascade Layers が Google Chrome 99 で実装されるという事なので勉強してみます

まずは仕様確認

6.4. Cascade Layers - CSS Cascading and Inheritance Level 5

(layer)というとペイント系ツールの表示の(layer)とか CSS なら z-index とかのコンテンツ表示の(layer)を連想しますが 6.2. Cascading Origins - CSS Cascading and Inheritance Level 5 に新たな(layer)の加える話らしいです

試しに書いてみるとこんな感じ

<title>CSS @Layer test</title>
<style>
@layer base, value, override;

p {
  color:black;
  background-color: white;
}

@layer value {
  :root {
    --green: green;
    --blue: blue;
  }
}

@layer override {
  p {color: var(--green);}
  p.a {color: var(--green);}
  .b {color: var(--green);}
  .c {color: var(--green);}
  .d {color: var(--green);}
}

@layer base {
  p {color: var(--blue);}
  p.a {color: var(--blue);}
  .b {color: var(--blue);}
  p > span.c {color: var(--blue);}
  .d {color: var(--blue) !important;}
}
</style>
<p>Black text.</p>
<p class="a">Black text.</p>
<p><span class="b">Green text.</span></p>
<p><span class="c">Green text.</span></p>
<p><span class="d">Blue text.</span></p>

まず @layer の外の記述が @layer 内の記述より優先されます

CSS Selectorによる優先順位より @layer の概念の方が上なので、@layer の外の p への指定が @layer の内の p.a より優先されます

CSSでは先に記述された内容を後に記述した内容が上書きする仕組みになっていますが @layer を使うと名前単位でグループ化でき、 @layer の名前だけを先に記述することでもこの上書き順序を制御できます

@layer base;
@layer value;
@layer override;

この場合 @layer base@layer value、それを更に @layer override; が上書きする事になります

これを @layer base, value, override; とカンマ区切りで 1 にまとめることもできます

上記の例では @layer basep > span.c {color: green;} より @layer override.c {color: green;} の方が強くなっています

更に @layer より !important 方が優先されるので @layer としては下位でも @layer base の中の !important 付きの記述の方が他の @layer の中の !important がない記述より優先されます

あくまで上書きの優先順位なので、ある @layer から別 @layer のカスタムプロパティーを参照することは @layer による上位、下位に関係なくできます (同じカスタムプロパティーがあれば上書きは発生しますが)

更に @import で外部CSSを読み込む際に layer(...) として @import 先に丸ごと @layer の名前を設定することができます

この時 @import 先の CSS の中で @layer が使われていれば @layer は階層構造作るので @import 元/先で @layer の名前が重複しても意図しない上書きを避ける事ができます

@layer base;
@import url(default.css) layer(default);
@layer override {
    /* ... */
}
@import url(theme.css) layer(theme);

@layer base {
    /* ... */
}

@layer default {
    @layer base {/* ... */}
    @layer override {/* ... */}
}

@layer theme.override {
    /* ... */
}

とりあえずさっと調べた所ではこんな感じで CSS@layer 単位でまとめておくことで記述を追加したりリファクタリングの際に予期せぬ上書きを防ぐことができそうです