スタイルの適用範囲を限定する CSS の `@scope` ルール
`@scope` アットルールは特定のセレクタの範囲に限定したスタイルを適用するためのルールです。`@scope` のルールセットに 1 つの CSS セレクタを指定すると、そのセレクタがスコープのルートとなります。`@scope` ルール内のスタイルはそのセレクタの範囲内でのみ適用されます。
CSS の @scope アットルールは特定のセレクタの範囲に限定したスタイルを適用するためのルールです。@scope ルールは以下のように記述します。
@scope (.card) {
p {
color: red;
}
}@scope() はルールセットとして CSS のセレクタを指定します。例えば @scope(main) や @scope(.container) といった感じです。ルールセットで指定したセレクタがスコープのルートとなり、@scope ルール内のスタイルはそのセレクタの範囲内でのみ適用されます。
上記のコード例では、.card クラスが付与された要素内の p 要素にのみ color: red が適用されます。それ以外の p 要素には適用されません。
@scope の基本構文
記事の冒頭でも触れたように、@scope のルールセットに 1 つの CSS セレクタを指定すると、そのセレクタがスコープのルートとなります。下記のコード例では、article 要素内にのみ適用されるスタイルを指定しています。
@scope (article) {
/**
}@scope のリミット
to を使用してスコープのリミットを指定することもできます。スコープのリミットは範囲の下限として機能します。例えば、次のような HTML があるとしましょう。
<div class="container">
<p>text 1</p>
<div class="inner">
<p>text 2</p>
</div>
</div>@scope ルールでは .container 要素をスコープのルートとし、.inner 要素をスコープのリミットとして指定します。
@scope (.container) to (.inner) {
p {
color: red;
}
}この場合 .inner 要素は .container の範囲内に含まれていますが、同時に .inner 要素がスコープのリミットとして指定されているため、.inner 要素内の p 要素には p { color: red; } が適用されません。
スコープの下限にスコープのリミット自身を含めるかどうかは議論がありました。スコープのリミット自身を含めたい場合には @scope (.container) to (.inner > *) のように指定することで対応できることから、スコープのリミットを含めない仕様となりました。https://github.com/w3c/csswg-drafts/issues/6577
インラインスタイル @scope ルール
HTML 内で <style> 要素を使用してインラインスタイルとして @scope ルールを記述できます。その場合、@scope のルールセットの指定は省略され、<style> 要素の親要素がスコープのルートとなります。なお、スコープのリミットはルートは自動で設定されません。
<main class="main">
<div class="container">
<style>
@scope {
p {
color: red;
}
}
</style>
<p>text 1</p>
<div class="inner">
<p>text 2</p>
</div>
</div>
<p>test 3</p>
</main>上記のコード例では、<style> の親要素である .container 要素がスコープのルートとなり、.container 要素内の p 要素にのみ color: red が適用されます。
:scope 擬似クラス
@scope ブロック内で :scope 擬似クラスを使用できます。:scope 擬似クラスはスコープのルート要素を指定するために使用されます。つまり、scope(.card) ルール内での :scope は .card 要素を指すということです。
@scope (.card) {
:scope {
border: 1px solid #e0e0e0;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-width: 300px;
padding: 16px;
}
h2 {
font-size: 1.5rem;
font-weight: bold;
margin: 0;
}
p {
color: #333;
}
}@scope の競合の解決
ある要素が複数の @scope ルールに含まれる場合、どちらのスタイルが適用されるのでしょうか?以下のように入れ子の構造の HTML があるとします。
<div class="section1">
<div class="section2">
<p>text</p>
</div>
</div>そして次の CSS では .section1 と .section2 それぞれに @scope ルールが適用されています。
@scope (.section1 .section2) {
p {
color: yellow;
}
}
@scope (.section2) {
p {
color: blue;
}
}
@scope (.section1) {
p {
color: red;
}
}このとき、p 要素には blue と red のどちらの色が適用されるでしょうか?正解は .section2 の @scope ルールによって color: blue です。
@scope ルール内では従来の CSS のカスケードとは異なる基準が適用されます。CSS の通常のカスケードでは、詳細度がより高いスタイルが、同じ詳細度の場合は後に記述されたスタイルが適用されました。@scope ルール内ではスコープルートまでの距離が最も近い @scope ルールが適用されます。これをスコープの近接性と呼びます。
この例では p 要素に最も近い .section2 要素の @scope ルールが適用されます。なお、@scope のルールセットとして渡しているセレクタは優先度の計算に使用されません。そのため、.section1 .section2 というセレクタは .section2 というセレクタよりも詳細度が高いということにはならないため、より後ろに記述された .section2 の @scope ルールが適用されます。
なお、スコープの近接性のルールはスタイルの記述順よりも優先して適用されるものの、スタイルの詳細度や !important、@layer ルールなどより強い優先度を持つものには勝つことができないことに注意してください。以下の例では .section2 の @scope ルールのほうが近接しているにもかかわらず、.section1 の @scope ルールで使用されているスタイルの詳細度がより高いため、color: red が適用されます。
@scope (.section2) {
p {
color: blue;
}
}
@scope (.section1) {
:scope {
p {
color: red;
}
}
}それでは @scope ルール内のスタイルと、通常の CSS のスタイルとの優先度の競合の場合にはどうなるでしょうか?
@scope (section) {
p {
color: blue;
}
}
p {
color: red;
}この場合にはどちらも同じ詳細度(0-0-1)を持ちますが、@scope ルール内のスタイルが優先して適用されます。
@scope の詳細度
@scope ルールのルールセットで使用されているセレクタは、@scope ブロック内のセレクタに影響を与えないという特徴があります。以下の例における p 要素は .card 要素内にのみ適用されるスタイルを指定していますが、詳細度は 0-0-1 となっています。
@scope (.card) {
p {
/* 詳細度 0-0-1 */
color: red;
}
}
/** スコープのルールセットのセレクタは影響しない */
@scope (.card p) {
p {
/* 詳細度 0-0-1 */
color: blue;
}
}
@scope (#card) {
p {
/* 詳細度 0-0-1 */
color: green;
}
}まとめ
@scopeルールは特定のセレクタの範囲に限定したスタイルを適用するためのルール@scopeのルールセットに 1 つの CSS セレクタを指定すると、そのセレクタがスコープのルートとなる@scopeルール内でtoを使用してスコープのリミットを指定することができる@scopeルール内で:scope擬似クラスを使用するとスコープのルート要素を指定できる@scopeルール内では新たなカスケードのルールとしてスコープの近接性が適用される。スコープの近接性はスコープルートまでの距離が最も近い@scopeルールが適用される@scopeルール内のスタイルと通常の CSS のスタイルとの優先度の競合の場合、@scopeルール内のスタイルが優先して適用される
