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については、記事『ウェブの新機能はいつまで待てば実践投入できるか』で詳しく紹介しています。

