Kodokon kodokon.com

カスケードレイヤー(@layer)と @scope

2つの新しいカスケード基準、すなわちレイヤーとスコープの近接性を使いこなし、詳細度の争いなしにスタイルを設計しましょう。

10 分 · 3 問

このレッスンを Kodokon で開く

カスケードは、順序づけられた基準を使って競合する宣言を解決します。オリジンと重要度、次にコンテキスト、次に style 属性のスタイル、次にレイヤー(@layer)、次に詳細度、そして最後に出現順です。決定的な点は、レイヤーが詳細度より前に評価されることです。したがって、優先度の高いレイヤーにある .button のルールは、優先度の低いレイヤーにある #nav div.menu a.button に打ち勝ちます。その (1,2,2) という詳細度は、レイヤー順序の前ではまったく意味を持ちません。これこそが @layer をデザインシステムの設計にとって非常に強力なものにしています。優先度はセレクタごとに争い取るのではなく、一度だけ、構造的に宣言されるのです。

CSS
@layer reset, base, components, utilities;

@layer components {
  .button { background: rebeccapurple; }
}

@layer base {
  button { background: gray; }
}
先頭での宣言が順序を確定します。ファイル内でのブロックの順序に関係なく、components が base に打ち勝ちます。

絶対に知っておくべき仕様上の細部が2つあります。1つ目。どのレイヤーにも属さないスタイルは、(通常の宣言においては)レイヤー化されたスタイルに打ち勝ちます。それらは最後に置かれる暗黙のレイヤーを形成するからです。したがって、あなたのローカルな上書きは、常にレイヤー化されたライブラリに勝ちます。2つ目。!important を使うと、順序が完全に逆転します。最初に宣言されたレイヤーが勝ち、レイヤー内の !important は、どのレイヤーにも属さない !important に打ち勝ちます。あなたの reset レイヤーの中の !important 宣言は、ほとんど打ち負かせないものになるのです。

CSS
@layer base, theme;

@layer base {
  a { color: black !important; }
}

@layer theme {
  a { color: purple !important; }
}
!important があると順序が逆転します。base が先に宣言されているため black が勝ちます。

@scope は、一連のルールをスコープのルートとオプションの下側の境界との間に区切ります。@scope (.card) to (.card__content) は、.card の子孫でありながら .card__content の外側にある要素を対象とします。これが有名なドーナツスコープで、注入されるコンテンツに漏れ出すことなくコンポーネントの枠組みをスタイリングするのに理想的です。内部では、:scope はルート自身を指します。そして @scope はまったく新しいカスケード基準、すなわち近接性を導入します。詳細度が等しい場合、スコープのルートが要素に最も近いルールが勝ちます。これはBEMも結合子も決して表現できなかったものです。

CSS
@scope (.card) to (.card__content) {
  :scope {
    padding: 1rem;
    border: 1px solid oklch(0.85 0.02 260);
  }
  img { border-radius: 8px; }
}
.card の枠組みの中の img 要素が対象になります。.card__content の中に注入されたものはスコープ外です。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. @layer a, b; があり、詳細度が等しい2つの通常宣言(1つは a に、もう1つは b に)がある場合、どちらが適用されますか?
    • 先に宣言された a のレイヤーのもの
    • b のレイヤーのもの。最後に宣言されたレイヤーが勝つから
    • レイヤーは無視され、ファイル内で最も後ろに現れるもの
  2. どのレイヤーにも属さない通常宣言が、あるレイヤーに置かれた通常宣言と対決します。結果は?
    • レイヤー化された宣言が常に勝つ
    • レイヤーに属さない宣言が勝つ
    • セレクタの詳細度が決める
    • ブラウザが競合を報告する
  3. @scope (.card) to (.card__content) において、内部のルールが対象にできる要素はどれですか?
    • 例外なく .card のすべての子孫
    • .card__content の外側にある .card の子孫(ドーナツスコープ)
    • .card__content とその子だけ