@layer で CSS の優先順位を「詳細度競争」から「順序の宣言」へ
スタイルが崩壊するのは詳細度を足して解決するからです。カスケード層は順序を明示します。層の間は順序のみ、層の内部では従来どおり詳細度で決まります。
長く続くプロジェクトには必ず !important が生えます。怠慢ではなく、詳細度を足す解決が続かないからです。今日一つクラスを足し、明日は二つ足してそれを押さえます。
カスケード層は発想を変えます。詳細度で競わず、先にいくつかのまとまりの順序を宣言します。
基本
@layer reset, base, components, utilities;
@layer base {
a { color: navy; }
}
@layer utilities {
.link-muted { color: gray; }
}
utilities が base の後にある限り、.link-muted は必ず勝ちます。base 側が a というより詳細な選択子でも関係ありません。
規則は三つです。
- 先頭の順序宣言がすべてを決める。 層の優先度は最初に現れた位置で決まり、中身には依存しません
- 層の間では詳細度を見ません。順序だけです
- 層の内部では従来どおり詳細度で決まります
三番目が重要です。@layer は詳細度を廃止せず、各層の内側に閉じ込めるだけです。
層に属さないスタイルが最強
どの @layer にも入っていない規則は、すべての層より強くなります。
@layer base {
.x { color: navy; }
}
.x { color: red; } /* 層外、勝つ */
この性質のおかげで移行が現実的になります。新しいコードは層へ、古いコードは層の外に置く。両者は共存できます。移行が終われば外側は空になります。
ただしここが最大の落とし穴でもあります。層を導入した当日、層外の古いスタイルが新しいスタイルを突然押さえます。一括で移すか、最下層(リセット、基本組版)から始めてください。
何が解決されるのか
| 問題 | 従来の対処 | 層を導入後 |
|---|---|---|
| ユーティリティが部品に負ける | 詳細度追加、!important |
ユーティリティを最後の層へ |
| 第三者スタイルの侵入 | 複製して書き換え | 第三者を最初の層へ |
| テーマ上書きが難しい | 選択子を探し回る | テーマ専用層を最後に |
| 並びが読み込み位置依存 | 注記でお願いする | @layer 一行で確定 |
最後の行が最大の利得です。 以前は読み込み順が結果を決め、その順序はビルド設定の中に隠れていました。今は源码に見える一行です。
入れ子
層の中に層を置けます。
@layer components {
@layer form, button;
}
副層の順序も同じく宣言で決まります。部品内の順序を表現できますが、二段までにしてください。それ以上は誰も順序を覚えられず、また推測に戻ります。
使うべきでない場合
- 単一ページでスタイルが僅かな場合:理解コストに見合いません
- 非対応ブラウザが要る場合:
@layerの塊は丸ごと無視されます(段階的劣化ではありません) !importantと混用する場合:!importantは層の順序を完全に反転させます(前の層が勝つ)。直感に反し、全体が見えなくなります
最後の点は重要です。!important の中では先に宣言した層が勝ちます。層の導入は !important を片付ける好機です。両者の混在はどちらか単独より保守が難しくなります。
カスケード層は CSS を簡単にしません。暗黙の詳細度計算を明示的な一行の宣言に置き換えるだけです。見える規則は、計算される規則より長く生きます。

コメント
…