直接用&写BEM嵌套会翻车,因&仅静态拼接字符串,不校验语义;正确做法是用@at-root #{&}__element生成扁平类名,禁用嵌套后代选择器及跨层修饰符。

直接用 & 写 BEM 嵌套,90% 的人会在第一层就翻车——它不自动补前缀,也不理解语义,只做静态字符串拼接。想靠嵌套“省事”反而生成 .card .card__title 这种带空格的后代选择器,完全违背 BEM 扁平命名原则。
为什么 &__item 在嵌套里会编译出空格?
Sass 的嵌套默认行为是:子选择器自动加空格前置。哪怕你写了 .card { &__title { ... } },Sass 也把它当作「.card 下的 &__title」来处理,最终输出 .card .card__title(注意中间空格)。
这不是 bug,是设计使然——& 只负责替换,不负责语义校验。
- 想得到真正的 BEM 类名
.card__title,必须跳出默认嵌套流 -
@at-root是最轻量、最可控的解法 - 别在
.card__header规则里再写&__logo,那会产出.card__header__logo,BEM 不允许三层结构
怎样用 & 安全生成 .block__element 和 .block--modifier?
只允许两种写法,其他都算高危操作:
-
.block { @at-root #{&}__element { ... } }→ 输出.block__element -
.block { @at-root #{&}--modifier { ... } }→ 输出.block--modifier
禁止:
- 在
&__element里面再嵌&--modifier,那会变成.block__element--modifier(语义错误:修饰符不该挂元素下) - 把
&放在伪类后面用,比如&:hover__icon,语法非法,Sass 直接报错 - 在媒体查询内写
&__item却指望它跨过@media层级去拼主类名——&引用的仍是外层块,但位置已错位
& 在 BEM 中最容易被忽略的兼容性陷阱
某些旧版 Dart Sass(@supports + & 的组合解析不稳定,可能漏掉前缀或报错;更隐蔽的是伪类连用问题:
-
.btn:not(.disabled) { &:hover { ... } }编译为.btn:not(.disabled):hover,没问题 - 但若写成
.btn:not(.disabled) { &__text { ... } },就会产出.btn:not(.disabled) .btn:not(.disabled)__text—— 浏览器直接拒解析 - 所有含函数式伪类(如
:nth-child(2))、属性选择器(如[data-id])的父选择器,都禁用&__拼接
真正安全的 BEM 写法,永远以最终 CSS 类名为准绳。写完 Sass,必须 grep 一遍输出文件,确认没有空格分隔的 .block .element,也没有重复出现的 & 字符串。

















