@scope(.selector)是CSS原生作用域机制,能限制样式仅在指定DOM子树内生效,但仅Chrome 125+、Firefox 117+、Safari 17.4+稳定支持,旧版本静默忽略;它通过作用域根定义生效起点,配合to()可选边界控制向下穿透范围,非编译时加属性也非运行时JS查询,而是浏览器原生解析的CSS规则。

@scope(.selector) 是什么,它真能限制样式范围?
能,但只在支持它的浏览器里生效——目前 Chrome 125+、Firefox 117+、Safari 17.4+ 才稳定支持,旧版本会直接忽略整个 @scope 规则,不报错也不生效。
它不是编译时加属性(像 Vue 的 scoped),也不是运行时 JS 查询(像 :scope 伪类),而是浏览器原生解析的 CSS 规则:指定一个“作用域根”,后续所有选择器都只在这个 DOM 子树内匹配。
例如:
@scope(.card) {
h2 { color: #6a0dad; }
.content { padding: 1rem; }
} 表示只有在 .card 元素内部的 h2 和 .content 才会被命中,外部同名元素完全不受影响。
@scope 中的 to() 边界控制容易被误解
to() 不是“到某个 class 就停”,而是“遇到第一个匹配的边界元素就终止作用域”——它只截断向下传播,不向上回溯,也不影响已进入作用域的子树。
常见误用:
@scope(.section) to(.end) {
p { color: green; }
} 如果 HTML 是 <div class="section"><p>text</p><div class="end"><p>still green</p></div></div>,第二个 p 依然生效,因为 .end 是 .section 的子元素,@scope 已经从 .section 开始生效,to(.end) 只阻止样式继续穿透到 .end 的后代,而不是把它当“结束标签”。
真正起效的边界必须是作用域根的**同级或更外层**元素,否则 to() 无意义。
立即学习“前端免费学习笔记(深入)”;
嵌套 @scope 和 :scope 伪类混用时的陷阱
@scope 块内写 :scope,它指向的是当前 @scope 的根元素,不是父级作用域或 document —— 这点和 JS 中的 element.querySelector(':scope') 行为一致,但仅限于该规则块内。
比如:
@scope(.card) {
:scope { border: 1px solid #e0e0e0; }
:scope h2 { font-weight: bold; }
} 这里的两个 :scope 都匹配 .card 自身,不是它里面的 h2。
注意::scope 在 @scope 块外单独写(如全局 div :scope span)仍然无效,它只在 @scope 内部或 JS 查询中才有语义。
为什么不能替代 Vue scoped 或 CSS Modules?
因为兼容性断层明显:生产环境若需支持 Chrome 124 或更早版本、大部分企业内网 IE/Edge Legacy、甚至部分安卓 WebView,@scope 就是不可用的。
它也不处理动态插入的 DOM(比如通过 innerHTML 添加的节点),那些节点不会自动纳入已有 @scope 的作用域;而 Vue 的 scoped 是编译时注入属性,CSS Modules 是构建时重命名类名,两者都对运行时插入内容有明确行为。
目前最稳妥的做法仍是:新项目可渐进启用 @scope 作局部优化,但主逻辑仍需兼容 fallback(比如同时写一份普通 class 选择器),或搭配 data-scope 手动模拟作用域边界。


















