CSSの新機能「@scope
アットルール」。このルールを使えば、CSSセレクターに適用されるスタイルのスコープ(範囲)をHTMLの特定の一部分に限定できます。さらに、その開始点(ルート)や終了点(リミット)も柔軟に設定できます。
この記事では、CSSのスコープを制御できる@scope
の基本的な使い方や注意点を解説します。
@scope
を使用すると、以下のようなメリットがあります。
- クラス名を複雑にしなくてすむ
- スタイルの衝突を防ぎやすくなる
- 保守性が高まる
.title
や.button
などのよく使うクラス名も、スコープごとにスタイルを分けられます。その結果、複雑なクラス名を増やさずにすみ、意図しないスタイルの上書きも防ぎやすくなります。また、スコープを設定することで影響範囲が明確になり、あとからスタイルを修正したり追加したりしやすくなります。
@scope
の使い方は大きく2通りに分けられます。それぞれ詳しく紹介します。
1.「スコープの開始点と終了点」を明示して使う場合
@scope
は、CSSファイル(外部CSS)やHTMLの<style>
要素など、いわゆるグローバルなCSSの中で、独立したブロックとして記述できます。この場合は、スコープルート(スコープの開始点)と、必要に応じてスコープリミット(スコープの終了点)をカッコ内に記述します。
基本的な構文は次のようになります。
@scope (スコープルート) to (スコープリミット) {
/* ルールセット */
}
- スコープルート:スコープを開始する要素を指定
- スコープリミット(省略可能):スコープを終了する要素を指定
次のように書くと、.section
の中にある<p>
要素だけにスタイルを適用できます。
@scope (.section) {
p {
color: green;
}
}
さらに、スコープの範囲を細かく制御したい場合は、to
を使ってスコープリミットを指定することもできます。次のように書くと、「.section_footer
から始まって.section_footer_textarea_inner
までの間にある<p>
要素にだけスタイルを当てる」ことができます。
▼ HTML
<div class="section">
<p>適用されません</p>
<div class="section_footer">
<p>適用されます</p>
<div class="section_footer_textarea">
<p>適用されます</p>
<div class="section_footer_textarea_inner">
<p>適用されません</p>
</div>
</div>
</div>
</div>
▼ CSS
@scope (.section_footer) to (.section_footer_textarea_inner) {
p {
color: green;
}
}
⚠️注意点
以下のHTML・CSSをご覧ください。
▼ HTML
<div class="section">
<p>適用されます</p>
<div class="section_footer">
<p>適用されません</p>
</div>
<!-- 🌟以下の<p>要素に color: green; は適用されるでしょうか? -->
<p>適用される?</p>
</div>
▼ CSS
@scope (.section) to (.section_footer) {
p {
color: green;
}
}
このスコープは『.section
から始まり、.section_footer
に入る直前まで』が対象範囲になります。最後の<p>適用される?</p>
に、color: green;
のスタイルは適用されるでしょうか?
答えは、適用されます。理由は、@scope (スコープルート) to (スコープリミット)
の仕組みにあります。この構文は、『スコープルートから始まり、スコープリミットの中に入るまでの要素にスタイルが適用される』という仕組みになっています。
スコープは「記述の位置」ではなく、「DOMツリー上での構造(内側か外側か)」に基づいて判断されるのがポイントです。.section_footer
の外側にある2つの<p>
要素は、どちらも同じ階層(兄弟要素)にあり、スコープ内と見なされます。一方で、.section_footer
の中にある<p>
要素は、スコープリミットの内側に含まれているため、スコープの範囲外となります。
2. 親要素を自動的にスコープのルートとする場合
@scope
は、HTMLの<style>
要素内にインラインスタイルとして記述することもできます。この場合、スコープのルートやリミットをカッコ内に書く必要はありません。<style>
要素の親要素が自動的にスコープルートとして扱われます。
次のコードをご覧ください。
▼ HTML
<div class="section">
<style>
@scope {
p {
color: green;
}
}
</style>
<p>適用されます</p>
<div>適用されません</div>
<div>
<p>適用されます</p>
</div>
</div>
<!-- ▼ 別のスコープのため、上記のスタイルは適用されない -->
<div class="section">
<p>適用されません</p>
</div>
この <style>
要素に書かれたp {}
のスタイルは、親要素である.section
の中すべての<p>
要素に適用されます。今回はto
セレクターでスコープの終了点(リミット)が指定されていないため、スコープは.section
全体になります。
そのため、たとえ<p>
要素が.section
の直下ではなく、入れ子になった<div>
要素の中にあっても、同じ.section
内にある限りスタイルが適用されます。
ポイントは以下です。
@scope
の前置き((ルート) to (リミット))
は省略される- スコープの対象は、
<style>
要素の親要素になる
コンポーネントごとにスタイルを閉じ込めたいときや、限定的にスタイルを適用したいときに便利です。
@scope
アットルールと:scope
疑似クラスの違い
ここまで紹介してきた@scope
アットルールとは別に、CSSには:scope
という疑似クラスも存在します。
:scope
疑似クラスは、使われる文脈によって意味は多少異なりますが、主に「スコープのルート要素を指定する」ことができます。詳しくは以下のMDNのページをご覧ください。
次のように、CSSのルート(グローバルな文脈)の中で単独で使用する場合は、:root
やhtml
セレクターと同じく、ページ全体のルートである<html>
要素への指定となります。
▼ CSS
/* ▼ <html> 要素全体への指定(:root {} や html {} と同等) */
:scope {
/* スタイル */
}
@scope
アットルールと:scope
疑似クラスを組み合わせて使用する
次のように、@scope
と組み合わせて使用することもできます。
▼ HTML
<div class="section">
<p>文字色は『オレンジ』です</p>
<div>文字色は『青』です</div>
<div>
<p>文字色は『緑』です</p>
<div>文字色は『青』です</div>
</div>
</div>
▼ CSS
@scope (.section) {
:scope {
color: blue;
}
:scope > p {
/* ▼ スコープルート(.section)直下の<p>のみオレンジ */
color: orange;
}
p {
/* ▼ スコープルート(.section)内のすべての<p>を緑に */
/* ▼ しかし上の「:scope > p {}」のほうが詳細度が高いので、スタイルが上書きされる */
color: green;
}
}
このコードでは、.section
をスコープルートとして@scope
を使い、範囲内の要素にスタイルを適用しています。
:scope { color: blue; }
:.section
自体に『青』を指定:scope > p { color: orange; }
:.section
直下の<p>
要素に『オレンジ』を指定p { color: green; }
:.section
内すべての<p>
要素に『緑』を指定(ただし『オレンジ』の指定の方が詳細度が高いため、.section
直下の<p>
要素は『オレンジ』)
ブラウザ対応状況
@scope
は2025年5月現在、Chrome・Edge 118(2023年10月)、Safari 17.4(2024年3月)以上で利用できます。
- 参照:Can I use…
まとめ
@scope
はInterop 2025で取り上げられています。そう遠くないうちに、すべての主要ブラウザで使えるようになるでしょう。便利な機能なので、ぜひ活用してみてください。
Interopについては、記事『ウェブの新機能はいつまで待てば実践投入できるか』で詳しく紹介しています。