Sass中&__element编译出空格是因为嵌套默认将子选择器视为“父选择器下的元素”,输出.card .card__title,违背BEM扁平原则;正确写法是@at-root #{&}__element生成无空格类名。

因为 Sass 的 & 不校验 BEM 语义,只做字符串拼接,而默认嵌套行为天然产出带空格的后代选择器——这直接违背 BEM 要求的扁平类名结构。
为什么 &__element 在嵌套里会编译出空格?
Sass 默认把子选择器当作「父选择器下的某元素」处理,哪怕你写了 .card { &__title { } },它也理解为「.card 下的 &__title」,最终输出 .card .card__title(注意中间空格)。这不是 bug,是设计逻辑:& 只替换,不判断是否该扁平。
- 验证方法:编译后 grep 输出文件,搜
.card .card__title这类带空格的字符串 - 真正有效的写法必须主动跳出嵌套流:
@at-root #{&}__element - 一旦出现空格,就失去 BEM 封装能力——样式依赖 DOM 层级,HTML 移动元素就失效
哪些嵌套写法会悄悄破坏 BEM 结构?
这些看似省事的写法,实际都在生成非 BEM 类名或语义错误的结构:
-
.card { .header { &__title { } } }→ 编译为.header__title(& 指向最近父级.header,不是.card) -
.card { &__header { &__title { } } }→ 编译为.card__header__title(BEM 禁止 Element 嵌套 Element) -
.btn:not(.disabled) { &__text { } }→ 编译为.btn:not(.disabled) .btn:not(.disabled)__text(函数式伪类 + & 拼接 = 无效 CSS) -
.card { &:hover { &__btn { } } }→ 编译为.card:hover .card:hover__btn(语法合法但语义混乱,且无法被 JS 控制)
状态类为什么不能靠伪类推导?
BEM 规定状态必须显式作为 Modifier 出现在 HTML 元素上,比如 class="btn btn--disabled"。靠 .btn:disabled 或 .btn-wrapper--disabled .btn 推导,会导致样式强耦合 DOM 结构,无法被测试、复用或响应式切换。
立即学习“前端免费学习笔记(深入)”;
- 正确做法:Sass 中统一用
&--disabled、&--hover,配合 JS 切换类名 - 禁止在块内写
&:hover { color: red; }—— 这会让 hover 状态脱离组件控制流 - 媒体查询内慎用 &__xxx:
@media (min-width: 768px) { &__icon { } }仍会正常拼出.card__icon,但若嵌套过深,& 引用可能错位
最易被忽略的点是:BEM 不是命名格式,而是职责约束。写对 &__item 只是第一步,关键得确保 HTML 同时存在 block 和 block__item 两个类——缺一不可,否则编译出来的类名根本不会匹配生效。


















