t28.dev

仕様と照らし合わせながら CSS カスケードレイヤーのふるまいをメモする

2025/11/15
Tech

CSS の C (Cascading) を見つめ直す” のおかげで CSS のカスケードがちょっと1分かったので、早速、

Widely available になってから 1年以上経っている。 また、いくつかの UIコン ポーネントCSS ラ イブラリでも使われるようになっている

カスケードレイヤー をいじってみる。

いじる

カスタムプロパティ (--color) 上書きしながら @layer のふるまいを検証する。

最初

body {
  background-color: var(--color);
}

--color が未定義だから、白背景 (playground)。

red レイヤーを追加

/** 👇️ */
@layer red {
  :root {
    --color: red;
  }
}

body {
  background-color: var(--color);
}

--color が定義された結果、赤背景になる (playground)

red レイヤーの後に blue レイヤー を追加

@layer red {
  :root {
    --color: red;
  }
}

/** 👇️ */
@layer blue {
  :root {
    --color: blue;
  }
}

body {
  background-color: var(--color);
}

Cascade layers (like declarations) are ordered by order of appearance. (…) then for normal rules the declaration whose cascade layer is last wins, (…)

ref: https://www.w3.org/TR/css-cascade-5/#cascade-layering

レイヤーは出現順に並べられ、最後にある宣言が優先される。 そのため、青背景になる (playground)。

blue レイヤーの後に green レイヤー を追加

@layer red {
  :root {
    --color: red;
  }
}

@layer blue {
  :root {
    --color: blue;
  }
}

/** 👇️ */
@layer green {
  :root {
    --color: green;
  }
}

body {
  background-color: var(--color);
}

最後に宣言された緑背景になる (playground)。

ファイルの先頭でレイヤーを宣言する

/** 👇️ */
@layer green, blue, red;

@layer red {
  :root {
    --color: red;
  }
}

@layer blue {
  :root {
    --color: blue;
  }
}

@layer green {
  :root {
    --color: green;
  }
}

body {
  background-color: var(--color);
}

@layer green, blue, red; でレイヤーの順番が決まっているので、その後に宣言した @layer green {} は記述の green レイヤーに割り当てられる。

Explicit layer identifiers provide a way to assign multiple style blocks to a single layer.

ref: https://www.w3.org/TR/css-cascade-5/#layer-names

そのため red レイヤーが最も優先度が高く、赤背景になる (playground)。

レイヤーの宣言をずらす

@layer red {
  :root {
    --color: red;
  }
}

/** 👇️ */
@layer green, blue, red;

@layer blue {
  :root {
    --color: blue;
  }
}

@layer green {
  :root {
    --color: green;
  }
}

body {
  background-color: var(--color);
}

@layer red{} の次に @layer green, blue, red; が宣言されているため、レイヤーの順番は red -> green -> blueになる。 そのため、青背景になる(playground)。

匿名レイヤーを追加する

@layer green, blue, red;

/** 👇️ */
@layer {
  :root {
    --color: yellow;
  }
}

@layer red {
  :root {
    --color: red;
  }
}

@layer blue {
  :root {
    --color: blue;
  }
}

@layer green {
  :root {
    --color: green;
  }
}

/** 👇️ */
@layer {
  :root {
    --color: purple;
  }
}

body {
  background-color: var(--color);
}

になる。匿名レイヤーは、宣言ごとに一意のものとして扱われる。

anonymous segments have unique identities for each occurrence.

ref: https://www.w3.org/TR/css-cascade-5/#layer-names

そのため上記のレイヤー順は:

  1. green
  2. blue
  3. red
  4. <anonymouse>
  5. <anonymouse>

になり、紫背景になる (playground)。

@layer を使わずに宣言する (implicit final layer)

/** 👇️ */
:root {
  --color: orange;
}

@layer green, blue, red;

@layer {
  :root {
    --color: yellow;
  }
}

@layer red {
  :root {
    --color: red;
  }
}

@layer blue {
  :root {
    --color: blue;
  }
}

@layer green {
  :root {
    --color: green;
  }
}

@layer {
  :root {
    --color: purple;
  }
}

body {
  background-color: var(--color);
}

@layer を使わない宣言は implicit final layer に追加される。

For the purpose of this step, any declaration not assigned to an explicit layer is added to an implicit final layer.

ref: https://www.w3.org/TR/css-cascade-5/#cascade-layering

final なので、レイヤー順において一番優先されるレイヤーになるため、オレンジ背景になる(playground)。

(余談) カスケードレイヤーが解決すること

ref: MDN - カスケードレイヤー - カスケードレイヤーが解決できる課題

大規模なコードベースでは、(…)

大規模なコードベースのスタイルは様々なところから提供される:

  • 複数のチーム
  • コンポーネントライブラリー
  • フレームワーク
  • サードパーティ

それらは作成者スタイルシート内でカスケードされる。辛すぎ。

多くのソースから提供されたスタイルが一緒にカスケードされること、(…)

チーム・人によってカスケード値を決める方法が違うかもしれない。辛すぎ。

詳細度の競合は、すばやくエスカレートする可能性があります。(…)

!important での解決はありがちだけれど、競合を通常の宣言から重要な宣言に移しているだけ。辛すぎ。

カスケードオリジンがユーザー、ユーザーエージェント、作成者スタイル間のパワーバランスを提供するのと同じように、カスケードレイヤーは、(…)

カスケードレイヤーはサブオリジンがあるかのように、構造的に整理する方法。

レイヤー内のルールは、レイヤー外のスタイルルールと競合することなく、互いにカスケードされます。(…)

カスケードレイヤーを使えば、レイヤーごとにスタイルを独立させられるので、細かい競合を気にせずに済む。嬉しすぎ。

レイヤーの優先順位は、常にセレクターの詳細度よりも優先されます。(…)

レイヤー間の詳細度の懸念はない。嬉しすぎ。

Footnotes

  1. ほんとうの意味で、ちょっと。