カスケードレイヤー

このレッスンはより高度な機能であるカスケードレイヤー を、CSS カスケードCSS 詳細度の基本概念を基に紹介することが目標です。

CSS が初めての方は、このレッスンを学ぶことは、このコースの他の部分よりも関連性が低く、少し学術的に見えるかもしれません。しかし、カスケードレイヤーとは何かという基本的なことを知っておくことで、自分のプロジェクトでカスケードレイヤーに遭遇したときに役立ちます。CSS で作業すればするほど、カスケードレイヤーを理解し、その力を活用する方法を知っていれば、異なる関係者、プラグイン、開発チームからの CSS でコードベースを管理する苦痛から解放されるでしょう。

カスケードレイヤーは、複数のソースからの CSS で作業する場合、CSS セレクターや詳細度が競合する場合に、!important の使用を検討している場合に最も適しています。

前提知識: カスケードと詳細度を含む、CSS はどう動くかに関する知識(CSS の第一歩およびカスケード、詳細度、継承を学習してください)。
目標: カスケードレイヤーの動作を知ること。

要素に適用される CSS の各プロパティには、1 つの値しかありません。ある要素に適用されるすべてのプロパティ値は、ブラウザー開発者ツールでその要素を検査することで確認できます。ツールの「スタイル」パネルには、検査対象の要素に適用されているすべてのプロパティ値と、一致するセレクター、CSS のソースファイルが表示されます。元からあるセレクターが優先され、その値が一致する要素に適用されます。

スタイルパネルには、適用されたスタイルに加えて、選択した要素に一致するが、カスケード、詳細度、ソース順のために適用されなかった値が、取り消し線で表示されます。取り消し線が引かれたスタイルは、優先順位は同じだが詳細度が低いオリジン間、またはオリジンと詳細度が一致するがコードベース内でより早く見つかったものである場合があります。適用されたプロパティ値には、多くの異なるソースから消し込まれた宣言がある可能性があります。もし、より詳細度の高いセレクターを持つスタイル設定が消された場合、その値はオリジンや重要度に欠けることを意味しています。

サイトの複雑さが増すと、スタイルシートの数も増え、スタイルシートのソース順序がより重要になると同時に、より複雑になることがよくあります。カスケードレイヤーは、このようなコードベースのスタイルシートの維持を簡素化します。カスケードレイヤーは明示的な詳細度格納器であり、最終的に適用される CSS 宣言をよりシンプルに制御することができます。

カスケードレイヤーを理解するためには、CSS のカスケードをよく理解する必要があります。下記の節では、カスケードの重要な概念を簡単にまとめています。

カスケードの概念のおさらい

CSS の C は "Cascading" (カスケード)の略です。スタイルが連鎖していく方式です。ユーザーエージェントは、すべての要素のすべてのプロパティに割り当てる値を決定するために、いくつかの、非常に明確に定義された手順を実行します。ここでは、これらの手順を簡単に説明し、ステップ 4 カスケードレイヤーを深く掘り下げていきますが、これがここで学ぶことです。

  1. 関連性: 各要素のセレクターが一致する宣言ブロックをすべて見つける。
  2. 重要度: ルールが通常か重要かに基づいて並べ替えます。重要スタイルとは、!important フラグを設定したものを指します。
  3. オリジン: 2 つの重要度バケットのそれぞれで、作成者、ユーザー、またはユーザーエージェントのオリジンでルールを並べ替えます。
  4. カスケードレイヤー: 6 つのオリジンの重要度バケット内で、カスケードレイヤーで並べ替えます。通常の宣言のレイヤーの順序は、最初に作成されたレイヤーから最後に、レイヤー化されていない通常のスタイル設定が続きます。この順序は重要スタイルでは逆になり、レイヤー化されていない重要スタイルが最も低い優先順位となります。
  5. 詳細度: オリジン層で優先的にスタイルを競わせるため、詳細度で宣言を並べ替えます。
  6. スコープ近接性: 優先順位を持つオリジンの 2 つのセレクターが同じ詳細度を持つ場合、スコープ内のルールのプロパティ値のうち、スコープルートまでの DOM 階層のホップ数が最も少ないものが優先されます。詳細と例えば、@scope の競合の解決方法を参照してください。
  7. 出現順: 優先順位を持つ元レイヤーの 2 つのセレクターが同じ詳細度を持つ場合、最も高い詳細度およびスコープ近接性を持つ最後に宣言されたセレクターからのプロパティ値が勝ちます。

それぞれの手順で、「現在実行中」の宣言だけが次の手順で「競争」するために移動します。実行する宣言が 1 つだけなら、その宣言が「勝ち」となり、その後の手順は無意味となります。

オリジンとカスケード

カスケードオリジンの種類は、ユーザーエージェントスタイルシート、ユーザースタイルシート、オーサースタイルシートの3種類です。ブラウザーは、各宣言をオリジンと重要度によって 6 つのオリジンバケットに分類します。優先順位は 8 段階あります。6つのオリジンバケット、トランジション中のプロパティ、そしてアニメーション中のプロパティです。優先順位は、最も低い優先順位を持つ通常のユーザーエージェントスタイルから、現在適用されているアニメーション中のスタイル、重要なユーザーエージェントスタイル、そして最も高い優先順位を持つトランジション中のスタイルへと進みます。

  1. ユーザーエージェントの通常スタイル
  2. ユーザーの通常スタイル
  3. 作成者の通常スタイル
  4. アニメーション中のスタイル
  5. 作成者の重要スタイル
  6. ユーザーの重要スタイル
  7. ユーザーエージェントの重要スタイル
  8. トランジション中のスタイル

「ユーザーエージェント」とはブラウザーのことです。「ユーザー」とは、サイトの訪問者のことです。「作成者」は、開発者であるあなたです。要素に <style> 要素で直接宣言されたスタイルは、作成者スタイルです。アニメーションやトランジションスタイルを含めない場合、ユーザーエージェントの通常スタイルの優先順位は最も低く、ユーザーエージェントの重要スタイルの優先順位は最も高くなります。

オリジンと詳細度

それぞれのプロパティについて、「勝つ」宣言は、重さ(普通か重要か)に応じて、オリジンから優先されるものです。レイヤーを無視して、最も高い優先順位を持つオリジンからの値が取得されます。勝利したオリジンが要素に対して複数のプロパティ宣言を保有する場合、それらの競合するプロパティ値のセレクターの詳細度が比較されます。異なるオリジンからのセレクターの間で詳細度が比較されることはありません。

下記の例には、2 つのリンクがあります。最初のリンクは作成者スタイルが適用されていないため、ユーザーエージェントスタイルのみが適用されます(ユーザースタイルがある場合は、そのスタイルも)。2 つ目は、作成者スタイルシート内のセレクターの詳細度が 0-0-0 であるにもかかわらず、作成者スタイルによって text-decorationcolor が設定されています。作成者スタイルが「勝つ」理由は、異なるオリジンからの競合スタイルがある場合、優先順位のないオリジンの詳細度に関係なく、優先順位のあるオリジンからのルールが適用されるからです。

このスタイルシートが書かれた時点で、ユーザーエージェントのスタイルシートにおける「競合する」セレクターは a:any-link であり、これは 0-1-1 という詳細度の重みを持ちます。これは作成者スタイルシートの 0-0-0 セレクターよりも大きいですが、現在のユーザーエージェントのセレクターが異なっていても、それは問題ではありません。作成者とユーザーエージェント由来の詳細度の重みは、決して比較されることはありません。詳細度の重みの計算方法について、もっと詳しく学んでください。

オリジンの優先順位は、常にセレクターの詳細度よりも優先されます。要素プロパティが複数のオリジンで通常のスタイル宣言でスタイル設定されている場合、作成者スタイルシートは、ユーザーまたはユーサーエージェントスタイルシートで宣言された冗長な通常プロパティが常に優先されます。スタイルが重要な場合、 ユーザーエージェントスタイルシートは、常に作成者スタイルやユーザースタイルよりも優先されます。カスケードオリジンの優先順位は、オリジン間の詳細度競合が決して起こらないことを確実にします。

移動する前にもう一つメモしておくと、現れる順番、または近接性は、優先されるオリジンで競合する宣言が同じ詳細度を持つ場合にのみ関係するようになります。

カスケードレイヤーの概要

これで「カスケードオリジンの優先順位」は理解できましたが、「カスケードレイヤーの優先順位」とは何でしょうか?カスケードレイヤーとは何か、どのように順序付けられるか、カスケードレイヤーにどのようにスタイルが割り当てるかについて説明することで、その疑問にお答えします。通常のレイヤー入れ子のレイヤー、無名レイヤーを扱います。まず、カスケードレイヤーとは何か、どのような課題を解決するのかについて説明します。

カスケードレイヤーの優先順位

オリジンと重要性に基づいて6段階の優先順位があるのと同様に、カスケードレイヤーによって、これらのオリジンの中にサブオリジンレベルの優先順位を作成することができます。

6 つのオリジンバケット内には、複数の カスケードレイヤーが存在することができます。レイヤーの作成順序は、多数の重要な意味を持ちます。作成順によって、オリジン内のレイヤー間の優先順位が設定されるからです。

通常のオリジンバケットでは、レイヤーは各レイヤーの作成順でソートされます。優先順位は、最初に作成したレイヤーから最後に作成したレイヤー、そしてレイヤーのない通常のスタイルが続きます。

この順序は、重要スタイルでは逆転します。レイヤー化されていない重要スタイルはすべて一斉に暗黙のレイヤーにカスケードされ、移行していない通常のスタイルよりも優先される。レイヤー化されていない重要スタイルは、重要なレイヤースタイルよりも低い優先順位がある。先に宣言されたレイヤーの重要スタイルは、同じオリジンで後続の宣言されたレイヤーの重要スタイルより優先される。

このチュートリアルの残りの部分では、作成者スタイルに限定して説明しますが、レイヤーはユーザーとユーザーエージェントのスタイルシートにも存在できることに留意してください。

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

大規模なコードベースでは、複数のチーム、コンポーネントライブラリー、フレームワーク、サードパーティからスタイルがもたらされることがあります。どんなに多くのスタイルシートが記載されていても、これらのスタイルはすべて単一のオリジンである作成者スタイルシートでカスケードされます。

多くのソースから提供されたスタイルが一緒にカスケードされること、特に一緒に作業していないチームから提供されたスタイルが一緒にカスケードされることは、問題を引き起こす可能性があります。チームごとに異なる手法を持っているかもしれません。あるチームは詳細度を縮小することをベストプラクティスとし、別のチームは各セレクターに id を含めることを標準仕様としているかもしれません。

詳細度の競合は、すばやくエスカレートする可能性があります。ウェブ開発者は、!importantフラグを追加することで、「すばやく修正する」かもしれません。これは簡単な解決策のように感じられるかもしれませんが、多くの場合、詳細度の争いを通常の宣言から重要な宣言に移されるだけです。

カスケードオリジンがユーザー、ユーザーエージェント、作成者スタイル間のパワーバランスを提供するのと同じように、カスケードレイヤーは、あたかもオリジンの各レイヤーがサブオリジンのように、単一のオリジン内の懸念を整理しバランスをとるための構造的な方法を提供します。レイヤーは、チーム、成分、サードパーティごとに作成することができ、レイヤーの順序に基づいてスタイルが優先されます。

レイヤー内のルールは、レイヤー外のスタイルルールと競合することなく、互いにカスケードさ れます。カスケードレイヤーは、スタイルシート全体を他のスタイルシートよりも優先させることができ、これらのサブオリジン間の詳細を気にする必要がありません。

レイヤーの優先順位は、常にセレクターの詳細度よりも優先されます。優先順位のあるレイヤーのスタイル設定は、優先順位の低いレイヤーに「勝ち」ます。負けたレイヤーにあるセレクターの詳細度は関係ありません。レイヤーの中で競合するプロパティ値に対しては、依然として詳細度が重要ですが、各プロパティに対して最も優先度の高いレイヤーだけが考慮されるため、レイヤー間の詳細度の懸念はありません。

カスケードレイヤーの入れ子で解決できる課題

カスケードレイヤーは、入れ子のレイヤーを作成することができます。各カスケードレイヤーは、入れ子のレイヤーを格納することができます。

例えば、コンポーネントライブラリーを components レイヤーにインポートすることができます。通常のカスケードレイヤーでは、コンポーネントライブラリーが作成者のオリジンに追加され、他の作成者スタイルとの詳細度の競合が取り除かれます。components レイヤーの中で、開発者は様々なテーマを定義することができ、それぞれが別個の入れ子のレイヤーとして定義されます。この入れ子になったテーマレイヤーの順序は、ビューポートサイズや方向などのメディアクエリーに基づいて定義することができます(下記のレイヤー作成とメディアクエリーの節を参照してください)。このように入れ子になっているレイヤーは、詳細度によって競合しないテーマを作成する方法を提供するものです。

レイヤーを入れ子にする機能は、コンポーネントライブラリーやフレームワーク、サードパーティーのウィジェット、テーマなどを開発する作業をしている人にとって、とても有益な機能です。

レイヤーを入れ子にして作成することで、レイヤー名が競合する心配もなくなります。この節では、入れ子のレイヤーに応じた説明をします。

「既定値、第三者のライブラリー、テーマ、コンポーネント、オーバーライド、他にもスタイル設定を表すレイヤーを作成することができ、各レイヤー内のセレクターや詳細度を変更したり、レイヤー間の競合を解決するために外観の順序に頼ったりすることなく、明示的な方法でレイヤーをカスケードレイヤーで並び替えることができます。」

Cascading and Inheritance specification.

カスケードレイヤーの作成

レイヤーは、以下のいずれかのメソッドで作成することができます。

  • @layer 文のアットルールで、@layer の後に 1 つまたは複数のレイヤーの名前を続けて使用し、レイヤーを宣言します。これにより、スタイルを割り当てることなく、名前付きのレイヤーを作成することができます。
  • ブロック内のすべてのスタイル設定を名前または無名のレイヤーに追加する @layer ブロックのアットルールです。
  • @importルールに layer キーワードまたは layer() 関数を指定すると、取り込んだファイルのコンテンツがそのレイヤーに割り当てられます。

3 つのメソッドはすべて、その名前を持つレイヤーがまだ初期化されていない場合に、レイヤーを作成します。レイヤー名が @layer のアットルールまたは layer() による @import で指定されなかった場合、新しい無名 (unnamed) のレイヤーが作成されます。

メモ: レイヤーの優先順位は、作成された順番です。レイヤーに含まれないスタイル、すなわち「非レイヤースタイル」は、最終的な暗黙のラベルに一緒にカスケードされます。

レイヤーの入れ子について説明する前に、レイヤーを作成する 3 つの方法についてもう少し詳しく説明しましょう。

名前付きレイヤーのための @layer 文のアットルール

レイヤーの順序は、CSS に現れる順序によって設定されます。スタイルを割り当てることなく、@layer に続いて 1 つまたは複数のレイヤー名を使用してレイヤーを宣言することは、レイヤーの順序を定義する 1 つの方法です。

@layer は CSS のアットルールで、カスケードレイヤーを宣言し、複数のカスケードレイヤーがある場合に優先順位を定義するために使用します。以下、アットルールは掲載されている順番で 3 つのレイヤーを宣言します。

css
@layer theme, layout, utilities;

多くの場合、レイヤーの順序を完全に制御するために、CSSの最初の行をこの @layer 宣言(もちろん、サイトにとって意味のあるレイヤー名)にすることをお勧めします。

上記の文がサイトの CSS の最初の行である場合、レイヤーの順序は themelayoututilities となります。上記の記述の前にいくつかのレイヤーが作成された場合、これらの名前を持つレイヤーがまだ存在しない限り、これら 3 つのレイヤーが作成され、既存のレイヤーリストの最後に追加されます。しかし、同じ名前のレイヤーがすでに存在する場合、上記のステートメントは2つの新しいレイヤーだけを作成します。例えば、layout が既に存在していた場合、themeutilities だけが作成されますが、この場合のレイヤーの順番は、layoutthemeutilities となります。

名前付きまたは無名レイヤーのための @layer ブロックのアットルール

レイヤーは、ブロック @layer アットルールを使用して作成することができます。アットルール @layer の後に識別子とスタイルブロックが続くと、識別子がレイヤーの名前に使用され、このアットルールのスタイルがレイヤーのスタイルに追加されます。指定した名前のレイヤーがまだ存在しない場合、新しいレイヤーが作成されます。指定した名前のレイヤーがすでに存在する場合、スタイルは前回存在したレイヤーに追加さ れます。スタイルのブロックを @layer を使用して作成する際に名前が指定されなかった場合、アットルール内のスタイルは新しい無名のレイヤーに追加されます。

下記の例では、4 つのブロックと 1 つのインラインの @layer アットルールを使用しています。この CSS では、掲載されている順に以下のことを行っています。

  1. 名前付き layout レイヤーを作成します。
  2. 無名のレイヤーを作成します。
  3. 3 つのレイヤーのリストを宣言しています。layout はすでに存在しているので、themeutilities の 2 つのレイヤーのみを新しく作成します。
  4. 既に存在する layout レイヤーにスタイルを追加します。
  5. 2つ目の無名レイヤーを作成します。
css
/* file: layers1.css */

/* unlayered styles */
body {
  color: #333;
}

/* creates the first layer: `layout` */
@layer layout {
  main {
    display: grid;
  }
}

/* creates the second layer: an unnamed, anonymous layer */
@layer {
  body {
    margin: 0;
  }
}

/* creates the third and fourth layers: `theme` and `utilities` */
@layer theme, layout, utilities;

/* adds styles to the already existing `layout` layer */
@layer layout {
  main {
    color: #000;
  }
}

/* creates the fifth layer: an unnamed, anonymous layer */
@layer {
  body {
    margin: 1vw;
  }
}

上記のCSSでは、layout, <anonymous(01)>, theme, utilities, <anonymous(02)> の5つのレイヤーをこの順番で作成し、6番目の暗黙のレイヤーとして body スタイルブロックに格納したスタイルを作成しました。レイヤーの順序は、レイヤーが作成される順序であり、レイヤーのないスタイルの暗黙のレイヤーは常に最後になります。一度作成したレイヤーの順序を変更する方法はありません。

ここでは、layout という名前のレイヤーにいくつかのスタイルを割り当ててみました。もし名前付きのレイヤーがまだ存在しない場合、レイヤーにスタイルを割り当てるかどうかにかかわらず、@layer アットルールで名前を指定すると、レイヤーが作成されます。これは、既存のレイヤー名のシリーズの終わりにレイヤーを追加します。指定したレイヤーがすでに存在する場合、指定したブロック内のすべてのスタイルは、以前に存在したレイヤーのスタイルに追加されます - 既存のレイヤー名を再利用してブロック内でスタイルを指定しても、新しいレイヤーは作成されません。

無名レイヤーは、レイヤーに名前を付けずにスタイルを割り当てることで作成されます。無名レイヤーにスタイルを追加することができるのは、その作成時のみです。

メモ: レイヤー名を指定せずに @layer を使用すると、さらに無名レイヤーが作成されます。これは、前回存在した無名レイヤーにスタイルを追加することはありません。

アットルール @layer は、名前があってもなくてもレイヤーを作成し、名前があるレイヤーがすでに存在する場合はレイヤーにスタイルを追加します。最初の無名レイヤーを <anonymous(01)> と呼び、2つ目を <anonymous(02)> と呼びましたが、これは説明するためだけのものです。これらは実際には無名レイヤーです。これらを参照したり、追加のスタイルを設定したりする方法はありません。

レイヤーの外で宣言されたスタイルはすべて、暗黙のレイヤーで一斉に結合されます。上の例のコードでは、最初の宣言で color: #333 プロパティを body に設定しています。これは、どのレイヤーの外側でも宣言されたものです。通常のレイヤー外宣言は、たとえレイヤー外スタイルの方が詳細度が低く、現れる順番が先であっても、通常のレイヤー宣言より優先されます。たとえコードブロックでレイヤー化されなかった CSS が最初に宣言されたとしても、これらのレイヤー化されなかったスタイルを格納した暗黙のレイヤーが、あたかも最後に宣言されたレイヤーであるかのように優先されるのは、このためです。

一連のレイヤーを宣言した @layer theme, layout, utilities; という行では、themeutilities というレイヤーだけが作成され、layout は最初の行で既に作成されています。この宣言は、すでに作成されたレイヤーの順序を変更しないことに注意してください。現在のところ、一度宣言したレイヤーの順序を変更する方法はありません。

次の例では、2 つのレイヤーにスタイル設定を割り当てることで、レイヤーを作成し、その過程で名前を説明しています。これらは最初の使用時に作成され、すでに存在しているため、最後の行で宣言しても何の意味もありません。

最後の行、@layer site, page; を最初の行に移動してみてください。どうなるでしょうか?

レイヤーの作成とメディアクエリー

メディアクエリーまたは機能クエリーを使用してレイヤーを定義した場合、メディアが一致しないか 機能に対応していなければレイヤーは作成しません。下記の例では、機器やブラウザーなどのサイズを変更すると、レイヤーの順序が変わる可能性があることを示しています。この例では、幅の広いブラウザーでのみ site レイヤーを作成しています。そして、page レイヤーと site レイヤーの順にスタイル設定を割り当てています。

幅の広い画面では、site レイヤーは最初の行で宣言され、sitepage より優先順位が低いことになります。そうでない場合は、site は狭い画面に後から宣言されるため、page より優先されます。もしうまく行かない場合は、メディアクエリーの 50em10em100em に変更してみてください。

@import でスタイルシートを名前付きまたは無名のレイヤーにインポート

@import ルールは、ユーザーが他のスタイルシートのスタイルルールを CSS ファイルに直接、または <style> 要素にインポートできるようにします。

スタイルシートをインポートする場合、@import 文はスタイルシートまたは <style> ブロック内の任意の CSS スタイルの前に定義しなければなりません。import 文はスタイルの前に最初に記述しなければなりませんが、その前に @layer アットルールを記述することで、レイヤーにスタイルを割り当てることなく、1つ以上のレイヤーを作成することができます。(@import の前には、@charset ルールを置くこともできます。)

このスタイルシートは、名前付きレイヤー、入れ子の名前付きレイヤー、または無名レイヤーのいずれかにインポートすることができます。以下では、スタイルシートをそれぞれ components レイヤー、components レイヤー内の入れ子の dialog レイヤー、無名レイヤーにインポートしています。

css
@import url("components-lib.css") layer(components);
@import url("dialog.css") layer(components.dialog);
@import url("marketing.css") layer();

複数の CSS ファイルを単一のレイヤーにインポートすることができます。以下の宣言は、2 つの別個のファイルを単一の social レイヤーにインポートしています。

css
@import url(comments.css) layer(social);
@import url(sm-icons.css) layer(social);

メディアクエリー機能クエリーにより、特定の条件に基づいてスタイルを読み込んでレイヤーを作成することが出来ます。次の例は、ブラウザーが display: ruby に対応していて、インポートするファイルが画面の内側へ依存する場合のみ、スタイルシートを international レイヤーにインポートします。

css
@import url("ruby-narrow.css") layer(international) supports(display: ruby) and
  (width < 32rem);
@import url("ruby-wide.css") layer(international) supports(display: ruby) and
  (width >= 32rem);

メモ: スタイルシートをリンクする <link> の方法に相当するものはありません。スタイルシート内で @layer を使用できない場合、スタイルシートをレイヤーにインポートするために @import を使用します。

入れ子のカスケードレイヤーの概要

入れ子のレイヤーは、名前付きまたは無名レイヤーの中にあるレイヤーです。それぞれのカスケードレイヤーは、無名レイヤーであっても、入れ子のレイヤーを格納することができます。他のレイヤーにインポートされたレイヤーは、そのレイヤー内の入れ子のレイヤーとなります。

入れ子のレイヤーの利点

レイヤーを入れ子にすることで、他のチームがレイヤーに取り込むかどうかを気にすることなく、カスケードレイヤーを作成することができます。同様に、入れ子によって、スタイルシート自体にレイヤーがあるかどうかを気にすることなく、サードパーティーのスタイルシートをレイヤーにインポートすることができるようになります。レイヤーを入れ子にできるため、外部スタイルシートと内部スタイルシートでレイヤー名が競合する心配がありません。

入れ子のカスケードレイヤーの作成

入れ子のレイヤーは、通常のレイヤーで記述されているのと同じ方法で作成することができます。例を説明すると、@layer というアットルールの後に、ドット表記で1つ以上のレイヤー名を記述することで作成することができます。複数のドットとレイヤー名に よって、複数の入れ子を表します。

ブロック @layer アットルールの中に別のブロック @layer アットルールを名前の有無にかかわらず入れ子にすると、入れ子にしたブロックは入れ子にしたレイヤーとなります。同様に、スタイルシートが layer キーワードまたは layer() 関数を含む @import 宣言でインポートされると、スタイルはその名前付きまたは無名のレイヤーに割り当てられます。もし @import 文にレイヤーが格納されていれば、それらのレイヤーはその名前付きまたは無名のレイヤーの中に入れ子になったレイヤーとなります。

以下、例を見ていきましょう。

css
@import url("components-lib.css") layer(components);
@import url("narrowtheme.css") layer(components.narrow);

最初の行では、components-lib.csscomponents レイヤーにインポートしています。このファイルにレイヤーが格納されている場合、ファイル名の有無にかかわらず、そのレイヤーは components レイヤーの入れ子となります。

2 つ目の行は、narrowtheme.csscomponents のサブレイヤーである narrow レイヤーにインポートしています。入れ子になった components.narrow は、components レイヤーの最後のレイヤーとして作成されます。ただし、components-lib.css がすでに narrow レイヤーを格納している場合は、 narrowtheme.css の成分が components.narrow 入れ子のレイヤーに付加されることになります。入れ子の名前付きレイヤーは、components.<layerName>というパターンを使用して、components レイヤーに追加することができる。前述したように、名前のないレイヤーを作成することはできますが、その後にアクセスすることはできません。

別な例を見てみましょう。 layers1.css を名前付きレイヤーにインポートする場合、次の文を使用します。

css
@import url(layers1.css) layer(example);

これは、 example という名前の単一レイヤーを作成し、そこにいくつかの宣言と、 5 つの入れ子のレイヤー、 example.layout, example.<anonymous(01)>, example.theme, example.utilities, example.<anonymous(02)> が含まれます。

名前付きの入れ子レイヤーにスタイルを追加するには、ドット記法を使用します。

css
@layer example.layout {
  main {
    width: 50vw;
  }
}

レイヤーの順番に応じた優先順位の決定

レイヤーの順序は、その優先順位を決定します。したがって、レイヤーの順序はとても重要です。カスケードがオリジンと重要度でソートするのと同じように、カスケードでは各 CSS 宣言をオリジンのレイヤーと重要度でソートします。

通常のカスケードレイヤーの優先順位

css
@import url(A.css) layer(firstLayer);
@import url(B.css) layer(secondLayer);
@import url(C.css);

上記のコードでは、2 つの名前付きレイヤが作成されます(C.css は非レイヤーのスタイルの暗黙のレイヤーに追加されます)。 3 つのファイル (A.css, B.css, C.css) は、その中に追加のレイヤーを格納しないことを想定しています。以下は、これらのファイルの内側と外側で宣言されたスタイルが、最も優先順位の低い (1) から最も高い (10) まで並べ替えられる場所を示すリストです。

  1. firstLayer の通常スタイル (A.css)
  2. secondLayer の通常スタイル (B.css)
  3. 非レイヤーの通常スタイル (C.css)
  4. インライン通常スタイル
  5. アニメーション中のスタイル
  6. 非レイヤーの重要スタイル (C.css)
  7. secondLayer の重要スタイル (B.css)
  8. firstLayer の重要スタイル (A.css)
  9. インラインの重要スタイル
  10. トランジション中のスタイル

レイヤー内部で宣言された通常スタイルは最も優先度が低く、レイヤーが作成された順番で並べ替えられます。最初に作成されたレイヤーの通常スタイルは最も低い優先順位を持ち、最後に作成されたレイヤーの通常スタイルはレイヤーの中で最も高い優先順位を持つ。言い換えれば、firstLayer 内で宣言された通常のスタイルは、競合が存在する場合、リスト上の後続のスタイル設定によって上書きされます。

次に、レイヤーの外側で宣言されたスタイルがあります。C.css のスタイルはレイヤーにインポートされていないので、firstLayersecondLayer で競合するスタイルがあれば、それを上書きすることになります。レイヤー内で宣言されていないスタイルは、レイヤー内で宣言されているスタイルよりも常に優先されます(important スタイルを除く)。

インラインスタイルは style 属性 を使用して宣言されます。この方法で宣言された通常のスタイルは、非レイヤーおよびレイヤー化されたスタイルシート (firstLayer - A.css, secondLayer - B.css, C.css) で得られる通常のスタイルよりも優先されます。

トランジション中のスタイルは、インラインの通常スタイルを含めるために、すべての通常スタイルよりも高い優先順位を持ちます。

重要スタイル設定、すなわち !important フラグを含むプロパティ値は、前回リストで紹介したどのスタイルよりも優先されます。これらは通常のスタイルと逆の順序で並べられます。レイヤーの外で宣言された重要スタイルは、レイヤー内で宣言されたスタイルよりも優先順位が低くなります。レイヤー内で得られる重要スタイルは、レイヤー作成順に並べられます。重要スタイルの場合、最後に作成されたレイヤーは最も低い優先順位を持ち、最初に作成されたレイヤーは宣言されたレイヤーの中で最も高い優先順位を持ちます。

インラインの重要スタイルは、他の場所で宣言された重要スタイルよりも高い優先順位を持ちます。

トランジション中のスタイルは、最も高い優先順位を持ちます。通常のプロパティ値が遷移する場合、他のすべてのプロパティ値の宣言に優先し、インラインの重要スタイルにも優先します(ただし、トランジションの間のみ)。

この例では、スタイル設定のないインラインレイヤー AB の 2 つのレイヤー、レイヤー設定のないスタイルのブロック、レイヤー AB の名前を付けたスタイルの 2 つのブロックがあります。

h1 要素に追加されたインラインスタイルは、style 属性を使用して、通常の color と重要な background-color を設定しています。通常のインラインスタイルは、レイヤーおよび非レイヤーのすべての通常スタイルを上書きします。重要なインラインスタイルは、すべてのレイヤー、レイヤー外の通常スタイルと重要な作成者スタイルを上書きします。作成者スタイルが重要なインラインスタイルを上書きする方法はありません。

通常の text-decoration と重要な box-shadowstyle インラインスタイルに属しませんので、オーバーライドすることができます。通常の非インラインスタイルでは、レイヤーがないスタイルが優先されます。重要スタイルでは、レイヤーの順序も重要です。通常のレイヤーなしのスタイルは、レイヤーに設定されたすべての通常のスタイルを上書きしますが、重要スタイルでは、優先順位が逆転します。レイヤーなしの重要スタイルは、レイヤーのスタイルより優先順位が低くなります。

レイヤーの中でだけ宣言される 2 つのスタイル設定は、通常の重要度を持つ font-style と、 !important フラグを持つ font-weight です。通常のスタイル設定の場合、最後に宣言された B レイヤーは、先に宣言された A レイヤーのスタイルを上書きします。通常のスタイル設定の場合、後のレイヤーが前のレイヤーより優先されます。重要スタイルでは、優先順位は逆転する。重要な font-weight の宣言では、最初に宣言したレイヤー A が、最後に宣言したレイヤー B よりも優先されます。

最初の行を @layer A, B; から @layer B, A; に変更することで、レイヤーの順序を逆にすることができます。試してみてください。これによってどのスタイルが取得され、どのスタイルが変わらないか?なぜでしょう?

レイヤーの順序は、CSS に現れるレイヤーの順序によって設定されます。最初の行では、スタイルを割り当てることなく、@layer の後にレイヤー名を使用し、セミコロンで終わり、レイヤーを宣言しています。この行を除外しても、結果は同じだったでしょう。なぜか?最初の行で 2 つのレイヤーを作成したため、@layer ブロックに A、B の順でスタイルルールを割り当てています。もしそうでなかったら、これらのルールブロックがこの順番で作成したはずです。

この 2 つの行を含めることができるのは、最初の行を編集して順序を簡単に入れ替えることができるようにするためと、2 つ目は、順序レイヤーを前もって宣言することが、レイヤー順序管理の最良の方法であることを見つけることが多いからです。

まとめると、次のようになります。

  • レイヤーの優先度の順序は、レイヤーを作成したときの順序です。
  • 一度作成すると、レイヤーの順序を変更する方法はありません。
  • 通常スタイルのレイヤーの優先順位は、レイヤーが作成される順序です。
  • レイヤーのない通常のスタイルは、通常のレイヤーのスタイルより優先されます。
  • 重要スタイルのレイヤーの優先順位は逆で、先に作成したレイヤーが優先されます。
  • レイヤーの重要スタイルはすべて、レイヤーのない重要な(および通常の)スタイルに優先します。
  • 通常のインラインスタイルは、レイヤーの有無にかかわらず、すべての通常スタイルに優先します。
  • 重要なインラインスタイルは、トランジション中のスタイルを除いて、他のすべてのスタイルに優先します。
  • 作成者スタイルが重要なインラインスタイルを上書きする方法はありません(トランジション時の一時的なものを除いて)。

入れ子になったカスケードレイヤーの優先順位

入れ子のレイヤーのカスケード優先順位は、通常のレイヤーと同様ですが、レイヤーの中に格納されます。優先順位は、入れ子のレイヤーの作成順序に基づきます。レイヤー内の入れ子でないスタイルは、入れ子の通常のスタイルよりも優先され、重要スタイルでは優先順位が逆転します。入れ子間の詳細度の重みは重要ではありませんが、入れ子内のスタイルが競合する場合は重要です。

以下は、components レイヤーと components.narrow 入れ子のレイヤーにスタイルを作成・追加し、新しい components.wide レイヤーにスタイルを作成・追加しています。

css
@import url("components-lib.css") layer(components);
@import url("narrowtheme.css") layer(components.narrow);

@layer components {
  :root {
    --theme: red;
    font-family: serif !important;
  }
}
@layer components.narrow {
  :root {
    --theme: blue;
    font-family: sans-serif !important;
  }
}
@layer components.wide {
  :root {
    --theme: purple;
    font-family: cursive !important;
  }
}

レイヤーのない通常スタイルは、レイヤーのある通常スタイルに優先し、レイヤー内では、入れ子のないスタイルは、入れ子のある通常スタイルに優先するので、は、他のテーマ色に優先します。

重要スタイルでは、レイヤースタイルは非レイヤースタイルより優先され、先に宣言されたレイヤーの重要スタイルが後に宣言されたレイヤーより優先されます。この例では、入れ子のレイヤーの作成順序は components.narrow の次に components.wide で、components.narrow の重要スタイルが components.wide の重要スタイルに優先し、つまり sans-serif が勝ちます。

スキルテスト

この記事の終わりまで来ましたが、最も重要な情報を覚えていますか?次に進む前に、この情報を覚えているかどうかを確認するためのテストがいくつかあります。スキルテスト: カスケードの課題 2 を見てください。

まとめ

この記事の内容をほぼ理解できたなら、上出来です。これで、CSS カスケードレイヤーの基本的な仕組みに慣れたことでしょう。次は、ボックスモデルについて詳しく見ていきます。