嵌套不等于作用域封装,需用 & 显式绑定父选择器生成 bem 类名,并用 @use 替代 @import 实现模块隔离,避免深层嵌套、:global() 滥用及逻辑混淆。

用 & 显式绑定父选择器,否则嵌套会意外泄露
很多人写 Sass 嵌套时直接缩进写子元素,比如:
.card {
width: 300px;
.title { color: #333; }
.content { font-size: 14px; }
}这看似封装了,但编译后是 .card .title 和 .card .content —— 它依赖 HTML 结构层级,一旦 .title 被挪到卡片外(比如调试时临时剪切),样式立刻失效;更糟的是,如果全局有另一个 .title,它可能被意外覆盖或干扰。真正的作用域封装得靠
&:用 &__title 或 &.is-active 明确表示“这是本组件的变体”,生成的是 .card__title 这类 BEM 风格类名,不依赖 DOM 深度,也不污染全局。
Sass 模块系统(@use)比 @import 更安全
@import 会把所有变量、混合宏、样式规则全部注入当前作用域,容易引发命名冲突和重复编译。比如两个模块都定义了 $primary-color,后者会静默覆盖前者。@use 则默认隔离:每个模块的变量、函数、混合宏必须加命名空间调用,例如:
@use 'base/variables' as base;
@use 'components/button' as btn;
.my-btn {
background-color: base.$primary-color;
@include btn.theme-dark;
}这样即使 button.scss 里也定义了 $primary-color,也不会干扰 variables.scss 的版本。注意:@use 必须放在文件最顶部,且同一个模块在单个文件中只应 @use 一次。
避免在嵌套中滥用 :global() 或 :local()
这些伪类常见于 CSS Modules 场景,但 Sass 本身不支持;如果混用 Webpack 的 css-loader + Sass,强行在 Sass 里写 :global(.legacy-header),会导致编译阶段无法校验选择器有效性,IDE 失去语法提示,重构时也找不到引用点。
更实际的做法是:把需要全局穿透的样式单独抽成 _reset.scss 或 _legacy.scss,用 @use 显式引入,并限制使用范围——比如只在老页面入口文件里 @use,新组件一律不引入。否则,一个 :global() 就可能让整个组件的样式隔离形同虚设。
嵌套层级超过 3 层就该警惕结构问题
Sass 允许无限嵌套,但编译出的 CSS 选择器权重会线性增长:.a .b .c .d .e 权重高达 500,轻则覆盖不了第三方 UI 库的 !important 规则,重则导致浏览器渲染性能下降(尤其在低配设备上反复计算匹配)。
遇到深层嵌套需求,优先考虑:
- 拆分子组件,用独立类名代替深度选择器
- 用
&--modifier替代.parent .child .grandchild - 检查是否误把逻辑判断写进了样式(比如用嵌套模拟状态机),该交给 JS 控制的 class 切换别硬塞进 Sass
& 和 @use 才是。很多人卡在“写了嵌套就等于封装了”的误解里,结果越写越难维护。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











