CSS @scope 作用域
開發網頁時,隨著架構複雜度的增加,管理 CSS 樣式也變得更加困難。為了避免樣式互相污染和提升維護性,CSS 加入了 @scope 規則定義,透過「作用域」的概念,讓開發者能更精確的控制樣式範圍,這篇教學會介紹 @scope 的概念、用法、嵌套、權重以及 :scope 虛擬類別選擇器的相互應用。
快速導覽:
教學影片
搭配教學影片一起閱讀,效果會更好!歡迎大家訂閱 STEAM 教育學習網的 Youtube 頻道。
認識 CSS @scope
@scope
是 CSS 裡的一種 At 規則,可以將樣式限制在某個 DOM 結構中 ( 或某個選擇器的範圍 ),通常 @scope
會用來解決樣式外漏 ( style leakage ) 或改善選擇器權重衝突,由於 @scope
提升讓 CSS 進階為模組化的架構,十分適合在元件導向的網頁開發,例如 Web Components 或大型 UI 區塊模組。
基本語法如下,使用小括號「()
」定義選擇器:
@scope (選擇器) {
樣式規則...
}
下方範例會透過 @scope
,讓只有 class
為 a 裡的 h2
變成紅色,其他的 h2
保持黑色。
<!-- HTML 程式碼 -->
<h2>apple</h2>
<div class="a">
<h2>oxxo</h2>
</div
<div class="b">
<h2>banana</h2>
</div>
<!-- CSS 程式碼 -->
<style>
@scope (.a) {
h2 {
color: red;
}
}
</style>
@scope 限制範圍
除了基本的用法,@scope
也可以透過「to
」去限制作用域的範圍,表示「範圍要延伸到的選擇器,但不包含該選擇器」,寫法如下:
@scope (起點選擇器) to (終點選擇器) {
/* 限定範圍內的樣式 */
}
下方範例會透過 @scope
搭配 to
,讓只有 a 裡的 h2
變成紅色,但在 a 裡頭的 b 裡的 h2
仍然保持黑色,範例同時列出使用「虛擬類別 :not
」選擇器的寫法,可以看出 @scope
的架構更容易理解且也更清晰。
<!-- HTML 程式碼 -->
使用 @scope
<div class="a">
<h2>我會變色</h2>
<div class="b">
<h2>我不會變色</h2>
</div>
</div>
使用虛擬類別 :not
<div class="c">
<h2>我會變色</h2>
<div class="d">
<h2>我不會變色</h2>
</div>
</div>
<!-- CSS 程式碼 -->
<style>
.a, .c {
border: 1px solid #000;
margin: 5px 0 20px;
}
@scope (.a) to (.b) {
h2 {
color: red;
}
}
.c > h2, .c *:not(.d) h2 {
color: red;
}
</style>
除了「虛擬元素」和「標籤選擇器」,@scope
支援其他所有選擇器語法,也可以使用「逗號」加入多組選擇器,下方範例會透過多組選擇器,限制在不同狀況下顏色會變成原本為預設的黑色 ( 在 b 裡、hover 時、有 title 屬性時 )。
<!-- HTML 程式碼 -->
<div class="a">
<h2>我會變色</h2>
<div class="b">
<h2>( .b 裡 ) 我不會變色</h2>
</div>
<h2>我會變色</h2>
<h2 title="test">( 有 title ) 我不會變色</h2>
</div>
<!-- CSS 程式碼 -->
<style>
@scope (.a) to (.b, [title], h2:hover) {
h2 {
color: red;
}
}
</style>
@scope 的權重
使用 @scope
時也需要遵守 CSS「權重」原則,但如果「作用域裡的選擇器權重和作用域外的權重相同」時,會優先使用作用域裡的選擇器,下方範例會展示權重的差異,當權重不同時,仍然以權重大的為主,當權重相同時,以 @scope
的樣式為主。
<!-- HTML 程式碼 -->
<div class="a">
<h2>我是 scope 定義紅色</h2>
<h3>我是外部定義綠色</h3>
</div>
<!-- CSS 程式碼 -->
<style>
/* 雖然放前面,但權重比較大,還是蓋過後面的 */
.a h3 {
color: green; /* 權重 0-1-1 */
}
@scope (.a) {
h2, h3 {
color: red; /* 權重 0-0-1 */
}
}
/* 雖然權重相同又放後面,但該選擇器位於 @scope 中,以 @scope 為主 */
h2 {
color: green; /* 權重 0-0-1 */
}
</style>
:scope 虛擬類別選擇器與「&」特殊符號
使用 @scope
時,可以額外使用 :scope
虛擬類別選擇器和 &
特殊符號,兩者說明如下:
:scope
:表示該作用域的「根元素」,類似整份 HTML 的:root
。&
:表示巢狀結構中的「自己」,也就是@scope
的選擇器本身。
下方範例會使用 :scope
定義 CSS 變數,該變數只會作用於 @scope
的範圍中。
<!-- HTML 程式碼 -->
<div class="a">
<h2>我 :scope 裡定義的顏色字體</h2>
</div>
<h2>我讀取不到變數,使用預設顏色字體</h2>
<!-- CSS 程式碼 -->
<style>
@scope (.a) {
:scope {
--c: red;
--size: 30px;
}
h2 {
color: var(--c);
font-size: var(--size);
}
}
h2 {
color: var(--c); /* 讀取不到,使用預設顏色 */
font-size: var(--size); /* 讀取不到,使用預設大小 */
}
</style>
下方範例會使用 &
代表自身選擇器,透過這種方式可以增加權重,因為加上了自身選擇器的權重,當權重相同時就會優先使用 @scope
裡的樣式。
<!-- HTML 程式碼 -->
<div class="a">
<h2>我有使用 & 增加權重,所以是紅色</h2>
<h3>我只是基本的 @scope</h3>
</div>
<!-- CSS 程式碼 -->
<style>
@scope (.a) {
& h2 {
color: red; /* 權重 0-1-1,權重相同時優先使用 @scope 裡的樣式 */
}
h3 {
color: red; /* 權重 0-0-1 */
}
}
.a h2, .a h3 {
color: green; /* 權重 0-1-1 */
}
</style>
@scope 嵌套的巢狀結構
雖然 @scope
已經是一個類似嵌套的巢狀結構,但裡面又放入另一個 @scope
之後,就更能實現層層套疊、各自隔離的樣式控制,讓同一份樣式在不同模組中可以擁有不同表現,不必額外增加許多選擇器進行權重控制管理,通常這種做法較適合大型 CSS 架構,在一般的使用情境較為少見。
<!-- HTML 程式碼 -->
<div class="a">
<div class="a1">
<h2>我在 .a1 裡面,是綠色</h2>
</div>
<div class="a2">
<h2>我在 .a2 裡面,是紅色</h2>
</div>
</div>
<!-- CSS 程式碼 -->
<style>
@scope (.a) {
h2 {
color: red;
}
@scope (.a1) {
h2 {
color: green;
}
}
}
</style>
@scope 和純粹使用選擇器的差異
當元素巢狀結構越複雜,要透過單純的邏輯與文件結構選擇器控制樣式,就會產生許多權重互相干擾的狀況,但 @scope
因為可以將選擇器限縮在指定的範圍,就可以在指定架構中輕鬆地調整樣式,下方範例會透過 @scope
和 :not
虛擬類別選擇器,分別控制 HTML 巢狀結構的元素樣式,可以看出兩者顯著的差異。
<!-- HTML 程式碼 -->
使用 @scope
<div class="a">
<h2>我是紅色</h2>
<div>
<h2>我是紅色</h2>
</div>
<div class="aa">
<div class="aaa">
<h2>我是黑色</h2>
</div>
<h2>我是綠色</h2>
</div>
</div>
使用 :not
<div class="b">
<h2>我是紅色</h2>
<div>
<h2>我是紅色</h2>
</div>
<div class="bb">
<div class="bbb">
<h2>我是黑色</h2>
</div>
<h2>我是綠色</h2>
</div>
</div>
<!-- CSS 程式碼 -->
<style>
.a, .b {
width: 200px;
border: 1px solid #000;
margin: 5px 0 20px;
}
h2 {margin: 5px;}
/* 使用 @scope */
@scope (.a) to (.aaa) {
h2 {color: red;} /* .a~.aaa 中的 h2 */
.aa h2 {color: green;} /* .a~.aaa 中的 .aa h2 */
}
/* 使用 :not 和文件結構 */
/* .b 第一層的 h2 和 .b 裡不包含 .bbb div 的第一層 h2 */
.b > h2,
.b div:not(.bbb)>h2{
color: red;
}
/* .b 的 .bb div 的第一層 h2 */
.b div.bb > h2 {
color: green;
}
</style>
小結
@scope
是一個讓 CSS 更具模組化的重要功能,不僅能限制樣式作用範圍,也改善了樣式覆蓋與衝突問題,隨著瀏覽器支援度提升,只要好好善用 @scope
,就可以撰寫出穩定又好維護的 CSS 喔。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~