sass 的 & 只做字符串拼接,不识别 bem 语义;&__element 会因空格或换行生成后代选择器(如 .card .card__header),违背 bem 扁平命名原则;正确写法是 @at-root #{&}__xxx 或直接写全名。

Sass 的 & 不认识 BEM,它只拼字符串;直接写 &__content 会产出带空格的后代选择器(如 .card .card__content),不是你要的扁平类名(.card__content)。
为什么 &__element 会编译出带空格的选择器
Sass 的 & 是“父选择器字符串原样替换”,不解析 BEM 语义。只要嵌套层级里有换行、缩进,或不小心多打一个空格(比如 & __icon 中间有空格),它就照单全收,生成含空格的选择器。
-
.card { &__header { } }→ 编译为.card .card__header(错误,带空格) - VS Code 自动补全、复制粘贴时极易混入不可见空格,
&__icon和& __icon编译结果完全不同 - 浏览器会匹配
.card .card__header,但这是后代关系,违背 BEM “扁平命名 + 无层级依赖” 原则
安全写法只有两种:手动写全名 或 @at-root #{&}__xxx
想得到真正的 .card__header,必须绕过默认嵌套行为。
- ✅ 推荐:用
@at-root #{&}__header显式提级,强制拼接:.card {<br> @at-root #{&}__header { color: #333; }<br>}→ 输出.card__header { color: #333; } - ✅ 更稳妥:不依赖
&,直接写全名:.card__header { color: #333; }彻底避免歧义,尤其适合团队协作或复杂组件 - ❌ 禁用:
&__header { ... }(无@at-root)、& __header(中间有空格)、&:hover { &__icon { } }(产出.btn:hover__icon非法名)
&--modifier 必须和块同级,不能嵌在伪类或子选择器里
修饰符是独立状态标识,不是某个状态下的派生类。语义上它应作用于块本身,而非其子元素或伪类上下文。
- ❌ 错误:
.btn {<br> &:hover {<br> &--active { color: red; }<br> }<br>}→ 编译为.btn:hover--active,浏览器直接忽略(非法类名) - ✅ 正确:
.btn {<br> &--primary { background: blue; }<br> &--disabled { opacity: 0.5; cursor: not-allowed; }<br>}→ 输出.btn--primary、.btn--disabled - ⚠️ 注意:如果需要“悬停时图标变色”,应写
.btn__icon { @at-root .btn--hover & { color: red; } },而非在&:hover内部再嵌套
循环生成 BEM 类名时,& 会指错对象
@each 中直接用 &__#{$part},& 仍指向外层块,导致输出带空格的选择器,破坏 BEM 扁平性。
- ❌ 危险:
.card {<br> @each $part in ("header", "body") {<br> &__#{$part} { padding: 1rem; }<br> }<br>}→ 输出.card .card__header、.card .card__body - ✅ 可靠方案一(
@at-root+ 插值):@each $part in ("header", "body") {<br> @at-root #{&}__#{$part} { padding: 1rem; }<br>} - ✅ 更推荐方案二(变量解耦):
$block: "card";<br>@each $part in ("header", "body") {<br> .#{$block}__#{$part} { padding: 1rem; }<br>}完全脱离&上下文干扰,可读性与可控性更强
真正容易被忽略的是:BEM 的 __ 和 -- 在 Sass 里只是普通字符,没有语法意义。你写的每一处拼接,都得自己确认最终 CSS 是否扁平、是否可复用、是否脱离 DOM 层级——光看 Sass 源码没用,必须检查编译后的 CSS 文件里有没有空格、有没有非法类名、有没有意外的权重膨胀。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











