BLOG
【CSS】セレクタの範囲を指定する@scope を使ってみた
INDEX
今回はGoogle Chrome 118 からサポートされたCSSの@scope
の使い方を紹介します。
こちらを使うとセレクタの適用範囲を簡単に指定することができます。
なお、執筆時点ではChromeとEdgeでのみサポートされています。
@scopeとは
cssの@scope
を使用すると、セレクタの範囲を設定できます。
範囲を設定するには、対象とするサブツリーの上限を決めるスコープルート(scoping root)を設定します。
スコープルートを設定すると、その中に含まれるスタイル(スコープ付きスタイルルール)はスコープルートの子孫要素に対してのみ適用されます。
HTML
<body>
<div class="top">
<p>top</p>
</div>
<div class="center">
<p>center</p>
</div>
<div class="bottom">
<p>bottom</p>
</div>
</body>
CSS
@scope(.center) {
p {
color: red;
}
}
表示
上記のコードでは、.content
でスコープされた定義の中にp
がセレクタとして用いられています。よって、これらのセレクタはp
なら何でもマッチするわけではなく、.content
の子孫であるp
にのみマッチします。
@scopeの下限を設定する
@scope
は、スコープの下限を設定できます。スコープの下限を設定するには、to
構文を用います。
HTML
<main>
<div class="header">
<h2 class="title">header</h2>
<p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
<div class="content">
<h2 class="title">content</h2>
<p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<div class="about">
<h3 class="title">about</h3>
<p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
</main>
CSS
/* 一部省略 */
@scope(.content) to (.about) {
.title {
text-align: center;
}
.text {
color: red;
}
}
表示
このスコープ付きスタイルルールは、.contents
要素の内側であり、かつ.about
の外側にある要素にのみ適用されます。
上限と下限を持つこの形式のスコープは、ドーナツスコープと呼ばれます。
:scopeセレクタ
デフォルトでは、全てのスコープ付きスタイルルールは、スコープルートからの相対パスとなります。
スコープルート自体をターゲットとする場合は:scope
セレクタを利用します。
@scope (.content) {
:scope {
/* .content全体にマッチ */
}
p{
/* .content内の<p>にマッチ */
}
}
実際は、スコープ付きスタイルルールのセレクタには全て:scope
が暗黙的に先頭に付与されています。
必要であれば明示することもでき、CSSのネストを使用して&
セレクタを先頭に追加することもできます。
@scope (.content) {
p {
/* .content内の<p>にマッチ */
}
:scope p {
/* 上記と同じ */
}
& p {
/* 上記と同じ */
}
}
スコープリミットに:scope
疑似クラスを使い、スコープルートとの関係を記述することもできます。
/* main直下の.contentまでが範囲 */
@scope (main) to (:scope > .content) { ... }
さらにスコープ外の要素を参照することもできます。
/* .asideの中にある場合のみ下限が設定される */
@scope (.content) to (.aside :scope .about) { ... }
ただし、スコープの外に出ていくことはできません。
:scope + p
のような記述は、スコープ内に無い要素を選択しようとするため無効です。
スコープ近接度
@scope
の導入に伴って、新たな基準『スコープ近接度』が導入されました。
異なるスコープルートを持つ複数のスタイルルールが重なった場合、スコープ内で宣言した要素と距離が一番近いスコープルートの宣言が優先されます。
HTML
<body>
<main>
<div>
<p>what's color?</p>
</div>
</main>
</body>
CSS
@scope (main) {
p { color: red; }
}
@scope (body) {
p { color: blue; }
}
上記のコードでは「main
のスコープの中のp
」と「body
のスコープの中のp
」に対して異なるスタイルを当てており、p
要素は2つのスタイル指定の両方を満たしています。
今回の場合はp
とmain
の距離が2、p
とbody
の距離が3となるので、より距離の近いスコープルートmain
のスタイルが適用されます。
ちなみに、スコープに属さないセレクタとスコープに属すセレクタをスコープ近接度で比較した場合、スコープに属すセレクタのほうが優先されます。
@scope (main) {
p { color: red; }
/* こちらが優先 */
}
main p { color: blue; }
注意点
注意点として、@scope
はセレクタの範囲を制限するものであり、スタイルの分離を提供するものではありません。子プロパティに継承されるプロパティは、@scope
の下限を超えても継承されます。
たとえば下記のcolor
プロパティは、ドーナツスコープの中にも継承されます。
CSS
@scope(.content) to (.about) {
:scope {
color: red;
}
}
表示
終わりに
今回は@scope
の基本的な使い方を紹介いたしました。
同じクラス名をつけた要素の1箇所だけスタイルを変えたい時など、今まではBEM記法を使って対応していましたが、@scope
を使うことでもっと簡単に対応できるようになりそうです。
執筆時点では対応ブラウザはChromeとEdgeのみとなっているため、使用する機会は少ないと思われますが、今後他のモダンブラウザでサポートされた際に使いこなせるよう覚えておくとよいでしょう。
参考
https://developer.chrome.com/docs/css-ui/at-scope?hl=ja