CSS 范围界定一直是一个挑战。默认情况下,样式是全局级联的,这意味着一个组件中的选择器可能会无意中影响另一个组件中的元素。多年来,开发人员采用命名约定、构建时工具和完整的 DOM 隔离来解决这个问题。该工具包的最新成员是 CSS @scope at 规则,它引入了基于邻近度的级联控制。本文比较了所有主要的范围界定策略,并帮助您选择正确的策略。
@scope At 规则
CSS 作用域模块级别 1 引入了 @scope,它将样式限制为指定的根元素及其后代。与命名约定不同,这是由浏览器强制执行的。
@scope (.card) {
.title { font-size: 1.25rem; font-weight: 600; }
.body { padding: 1rem; }
}
关键的创新是范围邻近性:无论选择器的特殊性如何,范围更接近元素的样式优先于范围更远的样式。您还可以定义范围限制来限制样式在树中应用的深度。
@scope (.card) to (.card__footer) {
.link { color: blue; }
}
/* Applies only within .card but stops before .card__footer */
这避免了嵌套卡问题——另一张卡内的卡不会继承外部卡的作用域样式。 Chrome 118+、Safari 17.4+ 和 Firefox 128+ 支持 @scope。
影子 DOM
Shadow DOM 提供了最强的封装形式。样式、标记和行为在影子根中完全隔离——CSS 不能泄漏或泄漏。
class MyCard extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: "open" });
shadow.innerHTML = `
<style>
.title { font-size: 1.25rem; }
</style>
<div class="title">Hello</div>
`;
}
}
customElements.define("my-card", MyCard);
Shadow DOM 对于需要绝对隔离的分布式小部件库和设计系统原语至关重要。但是,它增加了每个实例的运行时开销,并使 ::part() 和 ::slotted() 的跨界样式变得复杂。对于大多数应用程序组件,@scope 或 CSS 模块的隔离级别就足够了。
CSS 模块
CSS 模块在构建时生成本地范围的类名,从而防止冲突而无需运行时成本。
/* card.module.css */
.title { font-size: 1.25rem; }
.body { padding: 1rem; }
import styles from "./card.module.css";
function Card() {
return <div className={styles.card}>
<h2 className={styles.title}>Title</h2>
</div>;
}
构建工具将 .title 转换为唯一名称,例如 .card_title_3kl4s。优点包括零运行时开销、通过自动生成的类型定义进行 TypeScript 集成以及使用 composes 的可组合样式。限制是只有类选择器是有作用域的——元素和属性选择器仍然是全局的。
BEM 和命名约定
BEM(块元素修饰符)通过严格的命名来防止冲突:.block__element--modifier。它不需要构建工具并且可以立即理解。
<div class="card card--featured">
<h2 class="card__title">Title</h2>
<p class="card__body">Content</p>
<button class="card__btn card__btn--primary">Action</button>
</div>
BEM 在大型代码库中扩展性很差,因为没有实际的封装——级联泄漏仍然发生,并且类名由于深度嵌套而变得难以处理。 BEM 对于没有构建步骤的项目或遗留代码库迁移仍然很实用。
实用的范围界定策略
| 战略 | 封装 | 运行时成本 | 构建步骤 | 最适合 |
|---|---|---|---|---|
| 占位符_0 | 级联级 | 无 | 无 | 现代 CSS 中的组件作用域 |
| CSS 模块 | 班级级别 | 无 | 必填 | 基于框架的 SPA |
| 影子 DOM | 完整 DOM | 每个实例 | 无 | 分布式小部件、设计系统 |
| 边界元法 | 仅限会议 | 无 | 无 | 没有构建工具的项目 |
务实的混合方法效果最好:在组件文件中使用 CSS 模块进行类级作用域,添加 @scope 以在这些组件中进行级联管理,仅对可重用小部件库采用 Shadow DOM,并为全局实用程序类保留 BEM。 @scope at 规则代表了一种范式转变,首次将浏览器强制作用域引入 CSS,并使日常组件样式的级联管理变得更加简单。

