@scope
@scope CSS @ 規則使你能夠選擇特定 DOM 子樹中的元素,從而精確定位元素,而無需編寫難以覆蓋的、過於具體的選擇器,也無需將選擇器與 DOM 結構過於緊密地耦合。
在 JavaScript 中,可以透過 CSS 物件模型介面 CSSScopeRule 訪問 @scope。
語法
@scope @ 規則包含一個或多個規則集(稱為作用域樣式規則),並定義了將它們應用於所選元素的作用域。@scope 有兩種使用方式:
-
作為 CSS 中的獨立塊,這種情況下它包含一個序言部分,其中包括作用域根和可選的作用域限制選擇器——它們定義了作用域的上下邊界。
css@scope (scope root) to (scope limit) { /* … */ } -
作為 HTML 中
<style>元素內的內聯樣式,這種情況下序言被省略,其包含的規則集會自動限定在<style>元素的父元素範圍內。html<parent-element> <style> @scope { /* rulesets */ } </style> </parent-element>也可以將內聯
@scope與作用域限制選擇器結合使用,如@scope to (scope limit) { ... }。
描述
一個複雜的 Web 文件可能包含頁首、頁尾、新聞文章、地圖、媒體播放器、廣告等元件。隨著複雜性的增加,有效管理這些元件的樣式變得越來越重要,而有效的作用域樣式有助於我們管理這種複雜性。讓我們看下面的 DOM 樹:
body
└─ article.feature
├─ section.article-hero
│ ├─ h2
│ └─ img
│
├─ section.article-body
│ ├─ h3
│ ├─ p
│ ├─ img
│ ├─ p
│ └─ figure
│ ├─ img
│ └─ figcaption
│
└─ footer
├─ p
└─ img
如果你想選擇類名為 article-body 的 <section> 元素內的 <img> 元素,可以這樣做:
- 編寫像
.feature > .article-body > img這樣的選擇器。然而,這個選擇器特異性很高,難以覆蓋,並且與 DOM 結構緊密耦合。如果將來標記結構發生變化,你可能需要重寫 CSS。 - 編寫像
.article-body img這樣不那麼具體的選擇器。然而,這會選中該section內的所有圖片。
這就是 @scope 發揮作用的地方。它允許你定義一個精確的作用域,在此作用域內你的選擇器可以定位元素。例如,你可以使用一個獨立的 @scope 塊來解決上述問題,如下所示:
@scope (.article-body) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
.article-body 作用域根選擇器定義了規則集將要應用的 DOM 樹作用域的上限,而 figure 作用域限制選擇器定義了下限。因此,只有在類名為 article-body 的 <section> 內,但不在 <figure> 元素內的 <img> 元素才會被選中。
備註: 這種具有上下邊界的作用域通常被稱為甜甜圈作用域。
作用域的上限是包含的,而下限是排除的。要改變這種行為,你可以將任一選擇器與通用子代選擇器結合。例如,@scope (scope root) to (scope limit > *) 會使上下邊界都包含,@scope (scope root > *) to (scope limit) 會使上下邊界都排除,而 @scope (scope root > *) to (scope limit > *) 會得到一個排除的上限和一個包含的下限。
如果你想選擇類名為 article-body 的 <section> 內的所有圖片,可以省略作用域限制:
@scope (.article-body) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
或者,你可以將 @scope 塊內聯到 <style> 元素中,該元素又位於類名為 article-body 的 <section> 內部:
<section class="article-body">
<style>
@scope {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
</style>
<!-- ... -->
</section>
備註: 必須理解的是,雖然 @scope 允許你將選擇器的應用隔離到特定的 DOM 子樹中,但它並不能將應用的樣式完全隔離在這些子樹內。這一點在繼承方面最為明顯——會被子元素繼承的屬性(例如 color 或 font-family)仍將被繼承,超出任何設定的作用域限制。
@scope 塊中的 :scope 偽類
在 @scope 塊的上下文中,:scope 偽類提供了一種便捷的方式來直接為作用域根應用樣式,就像這樣:
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
}
以下是關於在 @scope 塊中使用 :scope 的一些注意事項:
-
:scope增加了類級別的特異性(詳情請見@scope 中的特異性)。 -
作用域限制可以使用
:scope來指定作用域限制和作用域根之間的特定關係要求。例如:css/* figure is only a limit when it is a direct child of the :scope */ @scope (.article-body) to (:scope > figure) { /* … */ } -
作用域限制可以使用
:scope引用作用域根之外的元素。例如:css/* figure is only a limit when the :scope is inside .feature */ @scope (.article-body) to (.feature :scope figure) { /* … */ } -
作用域樣式規則不能逃逸出子樹。像
:scope + p這樣的選擇是無效的,因為該選擇會超出子樹的範圍。 -
將作用域根和限制定義為選擇器列表是完全有效的,在這種情況下會定義多個作用域。在下面的例子中,樣式會應用於任何類名為
article-hero或article-body的<section>內的<img>,但如果它巢狀在<figure>內部則不應用:css@scope (.article-hero, .article-body) to (figure) { img { border: 5px solid black; background-color: goldenrod; } }
@scope 中的特異性
在 @scope 規則內部,普通選擇器和 & 巢狀選擇器的行為就像在選擇器前加上了 :where(:scope) 一樣。因為 :where() 的特異性為零,所以普通選擇器和 & 不增加權重。特異性權重由選擇器的其餘部分決定。例如,& img 選擇器的特異性等同於 :where(:scope) img 的特異性(0-0-1)。
警告: & 在 @scope 塊內的特異性處理方式因瀏覽器引擎和釋出版本而異。詳情請檢視瀏覽器相容性。
在下面的程式碼塊中,兩種情況下的特異性都僅來自 img:
@scope (.article-body) {
/* img has a specificity of 0-0-1, as expected */
img {
/* … */
}
/* & img also has a specificity of 0-0-1 */
& img {
/* … */
}
}
相比之下,顯式使用 :scope 會選中作用域根,並增加類級別的特異性(0-1-0),因為 :scope 是一個偽類。在下面的程式碼塊中,:scope img 的特異性為 0-1-1:
@scope (.article-body) {
/* :scope img has a specificity of 0-1-0 + 0-0-1 = 0-1-1 */
:scope img {
/* … */
}
}
@scope 衝突如何解決
@scope 為 CSS 層疊增加了一個新標準:作用域鄰近性。它指出,當兩個作用域有衝突的樣式時,應用那個與作用域根在 DOM 樹層級中“跳數”最少的樣式。讓我們透過一個例子來看看這意味著什麼。
以下面這段 HTML 片段為例,其中不同主題的卡片相互巢狀:
<div class="light-theme">
<p>Light theme text</p>
<div class="dark-theme">
<p>Dark theme text</p>
<div class="light-theme">
<p>Light theme text</p>
</div>
</div>
</div>
如果你像這樣編寫主題 CSS,就會遇到問題:
.light-theme {
background: #cccccc;
}
.dark-theme {
background: #333333;
}
.light-theme p {
color: black;
}
.dark-theme p {
color: white;
}
最內層的段落本應是黑色的,因為它在一個淺色主題的卡片內。然而,它同時被 .light-theme p 和 .dark-theme p 兩個選擇器選中。由於 .dark-theme p 規則在原始碼中出現得更晚,它被應用了,導致段落被錯誤地染成了白色。
要解決這個問題,你可以像下面這樣使用 @scope:
@scope (.light-theme) {
:scope {
background: #cccccc;
}
p {
color: black;
}
}
@scope (.dark-theme) {
:scope {
background: #333333;
}
p {
color: white;
}
}
現在,最內層的段落被正確地染成了黑色。這是因為它距離 .light-theme 作用域根只有一個 DOM 樹層級,而距離 .dark-theme 作用域根有兩個層級。因此,淺色樣式勝出。
正式語法
@scope =
@scope [ ( <scope-start> ) ]? [ to ( <scope-end> ) ]? { <block-contents> }
示例
作用域根內的基本樣式
在這個例子中,我們使用兩個獨立的 @scope 塊來分別匹配類名為 .light-scheme 和 .dark-scheme 元素內的連結。注意 :scope 是如何被用來選擇併為作用域根本身提供樣式的。在這個例子中,作用域根是應用了這些類的 <div> 元素。
HTML
<div class="light-scheme">
<p>
MDN contains lots of information about
<a href="/en-US/docs/Web/HTML">HTML</a>,
<a href="/en-US/docs/Web/CSS">CSS</a>, and
<a href="/en-US/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
<div class="dark-scheme">
<p>
MDN contains lots of information about
<a href="/en-US/docs/Web/HTML">HTML</a>,
<a href="/en-US/docs/Web/CSS">CSS</a>, and
<a href="/en-US/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
CSS
@scope (.light-scheme) {
:scope {
background-color: plum;
}
a {
color: darkmagenta;
}
}
@scope (.dark-scheme) {
:scope {
background-color: darkmagenta;
color: antiquewhite;
}
a {
color: plum;
}
}
結果
以上程式碼渲染效果如下:
作用域根和作用域限制
在這個例子中,我們有一個 HTML 片段,它與我們在描述部分前面談到的 DOM 結構相匹配。這個結構代表一個典型的文章摘要。需要注意的關鍵特徵是 <img> 元素,它們巢狀在結構的不同層級中。
這個例子的目的是展示如何使用作用域根和限制來為 <img> 元素設定樣式,從層級頂部開始,一直到(但不包括)<figure> 元素內的 <img>——實際上是建立了一個甜甜圈作用域。
HTML
<article class="feature">
<section class="article-hero">
<h2>Article heading</h2>
<img alt="image" />
</section>
<section class="article-body">
<h3>Article subheading</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam euismod
consectetur leo, nec eleifend quam volutpat vitae. Duis quis felis at
augue imperdiet aliquam. Morbi at felis et massa mattis lacinia. Cras
pharetra velit nisi, ac efficitur magna luctus nec.
</p>
<img alt="image" />
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<figure>
<img alt="image" />
<figcaption>My infographic</figcaption>
</figure>
</section>
<footer>
<p>Written by Chris Mills.</p>
<img alt="image" />
</footer>
</article>
CSS
在我們的 CSS 中,我們有兩個 @scope 塊:
- 第一個
@scope塊將其作用域根定義為類名為.feature的元素(在本例中,只有外部的<article>),展示瞭如何使用@scope為特定的 HTML 子集設定主題。 - 第二個
@scope塊也將其作用域根定義為類名為.feature的元素,但同時定義了一個作用域限制為figure。這確保了其中包含的規則集只會應用於作用域根(在本例中為<article class="feature"> ... </article>)內未巢狀在後代<figure>元素中的匹配元素。這個@scope塊包含一個單一規則集,為<img>元素設定了粗黑邊框和金色背景。
/* Scoped CSS */
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
figure {
background-color: white;
border: 2px solid black;
color: black;
padding: 10px;
}
}
/* Donut scope */
@scope (.feature) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
結果
在渲染出的程式碼中,請注意除了 <figure> 元素(標記為“我的資訊圖”)內的那個 <img> 之外,所有的 <img> 元素都被設定了粗邊框和金色背景。
規範
| 規範 |
|---|
| CSS 層疊與繼承第 6 級 # scoped-styles |
瀏覽器相容性
css.at-rules.scope
載入中…
css.selectors.nesting.at-scope
載入中…
另見
:scopeCSSScopeRule- 優先順序
- 在
@scope規則中定義&選擇器,來自 css.oddbird.net (2025) - 使用 CSS
@scope@ 規則限制選擇器的範圍,來自 developer.chrome.com (2023)