このシリーズでは、CSS の重要な概念であるカスケード(Cascade)の基礎を改めて学び直し、その応用としてカスケードレイヤー(@layer
)について説明していきます。
今回は CSS カスケードの仕組みを説明する基礎編です。
カスケードの仕組み
見出し「カスケードの仕組み」カスケード(Cascade)は「階段状に連続する滝」という意味ですが、 CSS(Cascading Style Sheets)では段階的に評価するアルゴリズムが存在しており、同じ要素に対してスタイルが競合すると、より優先度の高い指定によって上書きされます。
この優先度については詳細度(Specificity)が注目されがちですが、新たに導入されたカスケードレイヤーを含めていくつかの段階に分かれており、詳細度はその一部でしかありません。
順を追って説明していきますが、以下はそのカスケードの全体像を表現したウィジェットです。
ウィジェットの上部には 2 つのスイッチがあり、以下の機能を持っています。
- 「Open」を選択するとグループの下層が開く(下層がある場合)
- 「Append
!important
」を選択すると、下層に!important
の項目が追加される
その下の 6 つの項目が、カスケードのステップです。
評価順 | グループ名 | 概要 |
---|---|---|
1 | Origins | オリジン |
2 | Context | Shadow tree のコンテキスト |
3 | Layers, Inline Styles | カスケードレイヤーとインラインスタイル |
4 | Specificity | 詳細度 |
5 | Scoping Proximity | @scope の近接性 |
6 | Order of Appearance | 出現順 |
「Layers, Inline Styles」は、W3C の仕様書では「Element-Attached Styles」と「Layers」にそれぞれ分かれていますが、!important
の有無によって優先順位が前後し相互に影響するため、1 つのグループにまとめています。
これらの基準は上から順番に評価され、優先順位が同じ場合には下の基準へと遷移していきます。最後まで優劣がつかない場合には出現順(Order of Appearance)で決まります。
Origins
見出し「Origins」まずはオリジン(Origins)です。オリジンのみを抜き出したウィジェットを以下に表示します。
先頭の「Transitions」と「Animations」は、transition
と animation
が発生している間だけ適用される仮想のオリジンですが、ここでは気にせずに次の項目に進みます。
その下の 3 つのオリジン「Author」「User」「User-Agent」に注目します。
- Author
- User
- User-Agent
Author オリジンは、ウェブサイトやウェブアプリの制作者が作成したスタイルシートであり、style.css
ファイルや <style>
要素、style
属性で記述したスタイルのすべてが該当します。つまり、われわれが普段書いている CSS を指します。
User オリジンは、ブラウザを使用してウェブサイトを閲覧しているユーザが記述したスタイルシートです。拡張機能経由で使用したり、ブラウザにスタイルシートを読み込んでカスタマイズする方法が考えられます。
User-Agent オリジンは、ブラウザのデフォルトのスタイルシートです。例えば、すべての HTML 要素の display
プロパティの初期値は inline
ですが1、通常は User-Agent スタイルシートによって <p>
や <div>
といった要素に display: block
が指定されています。
この 3 つのオリジンは上から「Author > User > User-Agent」の順番で優先されるため、「User」や「User-Agent」のスタイルは「Author」で上書きすることができます。
!important
フラグ
この見出しのリンク続いて、!important
フラグを指定した状態を含めた優先順位を確認します。
- User-Agent
!important
- User
!important
- Author
!important
- Author
- User
- User-Agent
ここで注目する点は、通常の状態と比較して順位が反転しているということです。このルールによって「User-Agent !important
」が最優先されることがわかります。
例えば、User-Agent スタイルシートでは、<audio>
要素に以下の指定があります。
このコードは、controls
属性を指定していない <audio>
要素は絶対に表示されないことを意味します。つまり、Author スタイルシートや User スタイルシートで !important
フラグを使用したとしても display
の値を上書きすることはできません2。
このように、!imoprtant
フラグの役割は重要度を上げるだけではなく、カスケードの優先順位を反転させる効果があることを理解しておきましょう。
注意点としては、スタイルが管理しづらくなるので、Author スタイルシートにおいては !imoprtant
フラグの使用はなるべく控えましょう。明確な意図があるときのみ使用すべきで、その理由をコメントとして残しておくのが望ましいです。
最後に「Transitions」と「Animations」も含めた順位を確認しておきます。
- Transitions
- User-Agent
!important
- User
!important
- Author
!important
- Animations
- Author
- User
- User-Agent
オリジンの優先度が同一で決着がつかない場合には、次のステップに移動します。
revert
この見出しのリンクrevert
は、スタイルをリセットする目的で使用されることの多いキーワードですが、このキーワードを指定すると、オリジンの段階をロールバックする(差し戻す)ことができるため、現在のオリジンの指定が存在しないかのように振る舞います。
Author オリジンで使用した場合、まずは User オリジンまで戻りますが、User オリジンに該当する指定がなければ User-Agent オリジンまで戻ります。
もし、User-Agent オリジンにも該当する指定がなければ、unset
を指定したのと同様に扱われます。
Context
見出し「Context」コンテキスト(Context)は、Shadow DOM を使用したときの Shadow tree に対する基準です。Shadow DOM ではない場合には次のステップに進みます。
この「Host」が何を指しているかですが、Shadow tree の外側から ::part()
擬似要素を使用してスタイルを指定するケースが該当します。
以下のコードを例にすると、Shadow DOM で指定している background-color: black
は、::part()
で指定している background-color: teal
で上書きされます。
つまり、通常では内側のコンテキスト(Shadow)よりも、外側のコンテキスト(Host)のほうが強いということになります。
そして、先ほどのオリジン同様に !important
フラグを使用すると順位が反転します。
- Shadow
!important
- Host
!important
- Host
- Shadow
Layers, Inline Styles
見出し「Layers, Inline Styles」続いて、カスケードレイヤー(@layer
)とインラインスタイルです。
インラインスタイルについては説明するまでもないですが、HTML 要素に対して style
属性でスタイルを指定した場合が該当します。
それ以外の 3 つのレイヤーを見ていきましょう。
- Un-Layered
- Last Layer
- First Layer
「Un-Layered」とは、カスケードレイヤー(@layer
)を使用しない従来のルールセットです。
「Last Layer」「First Layer」はそれぞれ、最後に指定したレイヤーと最初に指定したレイヤーを意味しています。作成するレイヤーの数に制限はないですが、説明をシンプルにするために最初と最後の 2 つのレイヤーのみを対象としています。
具体的な CSS のコードを見てみましょう。
Un-Layered に加え、@layer
で first
と last
の 2 つのレイヤーを定義していますが、この場合は Un-Layered が優先されるので、color: teal
が適用されます。
また、これまでと同様に !important
フラグを付与すると順序が反転します。
- First Layer
!important
- Last Layer
!important
- Un-Layered
!important
- Un-Layered
- Last Layer
- First Layer
先ほどの CSS コードの各宣言に !important
フラグを追加すると、「First Layer」が一番強くなるので、color: blue
が適用されます。
最後に「Inline Style」も含めた順位を確認しておきます。
- Inline Style
!important
- First Layer
!important
- Last Layer
!important
- Un-Layered
!important
- Inline Style
- Un-Layered
- Last Layer
- First Layer
なお、カスケードレイヤー(@layer
)については、次回の記事で詳しく取り上げます。
Specificity
見出し「Specificity」詳細度(Specificity)は、セレクタの種類やその数によって優先度を決めるおなじみのルールですが、この段階になってようやく登場します。
この記事では詳しくは取り上げませんが、以下のルールでウェイト(優先度)が計算されます。
ID
見出し「ID」ID セレクタのウェイトは 1-0-0
です。#foo
のようなセレクタが対象です。
CLASS
見出し「CLASS」クラス、擬似クラス、属性セレクタのウェイトは 0-1-0
です。.bar
、:hover
、[type="radio"]
のようなセレクタが対象です。
TYPE
見出し「TYPE」要素、擬似要素のウェイトは 0-0-1
です。p
や ::after
のようなセレクタが対象です。
No Value
見出し「No Value」全称セレクタ(*
)、そして :where()
擬似クラスで指定したセレクタのウェイトは加算されないので 0-0-0
です。
これらのセレクタの組み合わせで詳細度が決まります。以下のように同じ要素に対するスタイルの指定であっても、セレクタの記述によってはウェイトが大きく異なります。
また、ウェイトは左の列から右の列に段階的に評価され、勝敗が決まった時点で確定します。
つまり、ID セレクタが 1 つだけで、クラスセレクタが仮に 10 個(またはそれ以上)指定されていたとしても、最初の段階で勝敗が決まるので ID セレクタが優先されます。
Scoping Proximity
見出し「Scoping Proximity」「Scoping Proximity」とはスコープの近接性のことで、スタイルが競合しているときにスコープ(@scope
)が近いほうの要素が優先されるルールです。
具体的には、@scope
規則をネストしているときに、詳細度(Specificity)までの優先度が同じであれば、このスコープの近接性が判断材料になります。
@scope
規則は W3C の仕様では「CSS Cascading and Inheritance Level 6」に属しており、草案(Working Draft)段階のため、実装方法や機能に変更が発生する可能性があります。また、現時点では主要ブラウザのなかでは Firefox が非対応ですが、Safari は 17.4 でサポートされました 🎉
このとき、3 番目に出現する最下層の .foo
は、親要素である .bar
から継承した font-weight: bold
が適用されますが、詳細度が同じ color
プロパティについては、近接性のルールから color: green
が適用されます。
ちなみに、この近接性は @scope
規則でのみ評価されるので、それ以外の通常のセレクタにおいては影響を受けません。前述のコードのスタイルを以下のように置き換えると、最下層の .foo
の近接性は考慮されずに .bar
から継承した color: blue
が適用されます。
Order of Appearance
見出し「Order of Appearance」ここまでで勝敗がついていない場合には、要素の出現順(Order of Appearance)で決まります。特筆すべきことはありませんが、より後ろに指定したスタイルが適用されます。
おわりに
見出し「おわりに」カスケードの評価基準は何段階にも分かれており、カスケードレイヤーやスコープの近接性のような新たな概念も加わっているため、一見すると複雑で難しく感じます。
しかし、これらの概念を正しく理解することで、スタイルの優先度が管理しやすくなり、より柔軟かつ堅牢なコードを維持することができるようになるでしょう。
ここで改めてカスケードの全体像を表現したウィジェットを掲載します。この記事をとおして、CSS カスケードへの理解の一助になっていれば幸いです。
次回はさらに進めて、優先度を制御する仕組みである、カスケードレイヤー(@layer
)について説明していきます。
参考文献
見出し「参考文献」本記事の作成にあたり、以下のウェブページを参考にしました。
- Introducing the CSS Cascade | MDN(外部リンクを開く)
- Cascade layers | MDN(外部リンクを開く)
- CSS Cascading and Inheritance Level 5 | W3C(外部リンクを開く)
- A Complete Guide to CSS Cascade Layers | CSS-Tricks(外部リンクを開く)
- The Future of CSS: Cascade Layers (CSS @layer) | Bram.us(外部リンクを開く)
- Getting Started With CSS Cascade Layers | Smathing Magazine(外部リンクを開く)
脚注
-
「Box Layout Modes: the
display
property | W3C」を確認すると、初期値がinline
であることがわかります。 ↩ -
controls
属性が指定されていなければ表示するものがないので当然といえば当然です。意図しない表示を防止するためのフールプルーフだと考えることができます。 ↩