カスケードレイヤー (@layer) は Widely available になってから 1年以上経っている。
また、いくつかの UIコン ポーネント・CSS ラ イブラリでも使われるようになっている。
そろそろキャッチアップしようと MDN を読んでいたが、カスケード自体はCSSの基本設計原則の1つであることを思い出した。
カスケードは、異なるソースから来るプロパティ値を組み合わせる方法を定義するアルゴリズムです。(…) これは カスケーディングスタイルシート という名前で強調されているように、 CSS の中心を占めるものです。
ref: CSS カスケード入門
新しい機能 (カスケードレイヤー) によってウェブ開発者は CSS でカスケードが使えるようになった…ではなく、 カスケードをより制御できるようになったが正確な理解である。 「じゃあ CSS のカスケードってなに?」と言われると言葉が詰まるので、CSS の C (Cascading) を見つめ直してから、カスケードレイヤーのキャッチアップをすることにした。
→ 2025/11/15 updated: “仕様と照らし合わせながら CSS カスケードレイヤーのふるまいをメモする”も書いた
CSS カスケードアルゴリズム
カスケードは
異なるソースから来るプロパティ値を組み合わせる方法を定義するアルゴリズム
ref: CSS カスケード入門
で、CSS カスケードアルゴリズムの役割は、
CSS プロパティの正しい値を決定するために CSS 宣言を選択すること
である。 例えば👇️のような競合するプロパティ値があるとき、前のルールを上書きすることが CSS のカスケードとして定義されている (playground)。
/* <h1>これは青い見出し</h1> */
h1 {
color: red;
}
h1 {
color: blue; /* 👈️ ソース上最後が勝つ */
}
カスケードによる並び替え
CSS のカスケードは以下の流れで最終的な値 (カスケード値)を選ぶ。
- ある要素に対して適用されるすべての宣言を集める
- 宣言を優先順位に従って並び替える
- 単一のカスケード値を出力する
The cascade takes an unordered list of declared values for a given property on a given element, sorts them by their declaration’s precedence as determined below, and outputs a single cascaded value.
ref: CSS Cascading and Inheritance Level 5 - 6. Cascading
カスケードの優先順位は以下のように決まっている (仕様とMDNの説明で差分がある?)。
| 順序 (低い順) | 仕様 | MDN の説明 |
|---|---|---|
| 1 | Filtering(ここだけ § 5 Filtering) | 関連性 |
| 2 | Origin and Importance | オリジンと重要度 |
| 3 | Context | (ない?) |
| 4 | Element-Attached Styles | (ない?) |
| 5 | Layers | (ない?) |
| 6 | Specificity | 詳細度 |
| 7 | (ない?) | スコープ近接性 |
| 8 | Order of Appearance | 出現順 |
さらに、それぞれの項目内にも優先順位がある。
Origin and Importance 内の優先順位は
- スタイルルールがどの層(出所)から来たかを示すオリジン
- 宣言に付けられた
!importantの有無
で決まる。 オリジンには3つのコアオリジンと
2つの追加オリジンがあり、
これらと !important の組み合わせで次のような優先順位になる:
順序(低い順) オリジン 重要度 1 ユーザーエージェント(ブラウザー) 通常 2 ユーザー 通常 3 作成者(開発者) 通常 4 CSS @keyframes アニメーション 5 作成者(開発者) !important6 ユーザー !important7 ユーザーエージェント(ブラウザー) !important8 CSS トランジション
Web アプリの開発で普通に CSS を実装すると、そのスタイルは作成者オリジン1由来になる。
ユーザーのスタイルより作成者のスタイルが優先されるのは少し不思議な気もしたが、!important を使えば逆に上書きできるようにすることでバランスを保つことが仕様になっている。
「上書きしたいからとりま !important」なコードを見ることもあるが、単純な上書きではなく、作成者-ユーザー-ユーザーエージェント間の優先度が逆転していることを知らないとハマりそうな予感。
Layers の優先順位は
@layerを使った explicit layer@layerを使わない implicit final layer
に分かれる。@layerで囲わない宣言は自動的に implicit final layer に入る。
implicit final layer は他の explicit layer より後に評価されるため、高い優先度で他の宣言を上書きする。
Declarations within each origin and context can be explicitly assigned to a cascade layer. For the purpose of this step, any declaration not assigned to an explicit layer is added to an implicit final layer.
並べ替えのイメージ
CSS カスケードは前述した優先度で並べ替えをして、そこで差がつかないときは次の基準で並べ替えをする。
The cascade sorts declarations according to the following criteria, in descending order of priority:
並べ替えを図示すると、👇️のような感じになる。
h1 / color
└─ [Origin & Importance (Normal)]
├─ User-Agent origin // ブラウザ既定
│ └─ h1 { color: black; }
├─ User origin // ユーザーによるスタイルCSS
│ └─ h1 { color: green; }
└─ Author origin // 作成者のスタイル
├─ [Layers] // Author origin の中で Layer の並べ替えをする
│ ├─ @layer base
│ │ └─ h1 { color: gray; }
│ └─ (implicit final layer) // レイヤーの中では、レイヤー指定なしが一番強い
│ └─ h1 { color: blue; }
└─ [Element-Attached Styles]
└─ <h1 style="color: orange"> 👈️ 勝ち!
Footnotes
-
オリジンの名前は結構表記ゆれしている。 仕様では
authore origin、author declarations、author style sheetの表記がある。 MDN も同じ感じでばらついている。 ↩