选择器作用域 ( @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 喔。
微信扫码关注
抖音扫码关注