@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 というより詳細な選択子でも関係ありません。

規則は三つです。

  1. 先頭の順序宣言がすべてを決める。 層の優先度は最初に現れた位置で決まり、中身には依存しません
  2. 層の間では詳細度を見ません。順序だけです
  3. 層の内部では従来どおり詳細度で決まります

三番目が重要です。@layer は詳細度を廃止せず、各層の内側に閉じ込めるだけです。

層に属さないスタイルが最強

どの @layer にも入っていない規則は、すべての層より強くなります。

@layer base {
  .x { color: navy; }
}
.x { color: red; }   /* 層外、勝つ */

この性質のおかげで移行が現実的になります。新しいコードは層へ、古いコードは層の外に置く。両者は共存できます。移行が終われば外側は空になります。

ただしここが最大の落とし穴でもあります。層を導入した当日、層外の古いスタイルが新しいスタイルを突然押さえます。一括で移すか、最下層(リセット、基本組版)から始めてください。

何が解決されるのか

問題 従来の対処 層を導入後
ユーティリティが部品に負ける 詳細度追加、!important ユーティリティを最後の層へ
第三者スタイルの侵入 複製して書き換え 第三者を最初の層へ
テーマ上書きが難しい 選択子を探し回る テーマ専用層を最後に
並びが読み込み位置依存 注記でお願いする @layer 一行で確定

最後の行が最大の利得です。 以前は読み込み順が結果を決め、その順序はビルド設定の中に隠れていました。今は源码に見える一行です。

入れ子

層の中に層を置けます。

@layer components {
  @layer form, button;
}

副層の順序も同じく宣言で決まります。部品内の順序を表現できますが、二段までにしてください。それ以上は誰も順序を覚えられず、また推測に戻ります。

使うべきでない場合

  • 単一ページでスタイルが僅かな場合:理解コストに見合いません
  • 非対応ブラウザが要る場合:@layer の塊は丸ごと無視されます(段階的劣化ではありません)
  • !important と混用する場合:!important は層の順序を完全に反転させます(前の層が勝つ)。直感に反し、全体が見えなくなります

最後の点は重要です。!important の中では先に宣言した層が勝ちます。層の導入は !important を片付ける好機です。両者の混在はどちらか単独より保守が難しくなります。

カスケード層は CSS を簡単にしません。暗黙の詳細度計算を明示的な一行の宣言に置き換えるだけです。見える規則は、計算される規則より長く生きます。

← 記事一覧に戻る

コメント

…