@at-root #{&}__element是唯一安全生成bem扁平类名的方式,因&__title会编译为.card .card__title(带空格后代选择器),违背bem要求的单类名.card__title;必须用@at-root提级至根作用域并插值拼接。

直接写 &__title 会编译出带空格的选择器
很多人以为 .card { &__title { } } 能生成 .card__title,结果却是 .card .card__title(带空格的后代选择器)。这不是 bug,是 SCSS 嵌套的默认逻辑:& 代表当前完整选择器字符串,拼接时保留原有空格和结构。
一旦父选择器含多个部分(如 .sidebar .widget),&__content 就变成 .sidebar .widget__content,但 BEM 只认 .widget__content —— 类名前缀必须严格对应块名,不能带上下文依赖。
- 错误场景:
.card { .header { &__title { } } }→ 编译为.card .header__title,语义错乱 - 更危险的是:
.button { &:hover { &__icon { } } }→.button:hover__icon,浏览器直接忽略该规则 - 真正生效的只有块级顶层的
&__xxx,且父选择器必须是单个类名(如.card)
@at-root #{&}__element 是唯一稳定提级方式
要生成真正的扁平类名(如 .card__header),必须跳出嵌套上下文,在 CSS 根层级定义。核心是用 @at-root + 插值 #{&} 获取纯块名(不含空格、伪类、属性),再拼接 __ 或 --。
示例:.card { @at-root #{&}__header { color: #333; } } → 输出 .card__header { };修饰符同理:@at-root #{&}--loading { opacity: .6; } → .card--loading。
- 块名是变量时(如
$block: "modal"),改用@at-root #{$block}__close { } - 禁止在
@media、&:focus、&[disabled]内部再用@at-root #{&}__xxx,输出顺序不可控,且破坏 BEM 层级语义 - 所有
__和--必须与块定义同级,不能嵌套进任何子容器或状态块中
循环生成修饰符时,$modifier 的值必须是带引号字符串
用 @each 批量生成 .btn--hover、.btn--disabled 等修饰符,常见错误是写成 @each $modifier in (hover, disabled) —— 这会被 SCSS 当作未定义变量,报错 Undefined variable "$hover"。
正确写法是把修饰符列表声明为字符串字面量数组:@each $modifier in ("hover", "disabled", "large") { .btn--#{$modifier} { /* 样式 */ } }。
- 若从 map 取值(如
map-keys($modifiers)),需确保 map 的 key 是字符串类型,否则map-keys返回的仍是无引号标识符,仍需额外转字符串 -
#{$modifier}本身不加引号,但$modifier的值必须是"hover"这样的字符串,不是hover - 连字符位置别写错:
.#{$block}__#{$element}-active中的-active可能被解析为减法,应写成.#{$block}__#{$element}--active或拆开拼接
手动写全名比依赖 & 更可靠
真实项目里,& 的行为完全取决于当前上下文:父选择器含空格、伪类、属性选择器,甚至跨文件 @import,都可能导致 &__xxx 拼出非法名或意外覆盖。
比如 .sidebar .widget { &__content { } } 生成 .sidebar .widget__content,但 HTML 里只写了 class="widget__content",样式就失效了 —— DOM 上少一个 class,比逻辑错误更难定位。
- BEM 的解耦效果不来自语法糖,而来自对类名显式归属的强制约束
- 哪怕 SCSS 编译正确,如果 HTML 没同步写全
card card--featured和card__title card__title--large,整个链路就断了 - 真正容易被忽略的是:命名规范最终靠人落地,工具只是校验器;
@at-root不是补救手段,而是暴露了嵌套设计本身的脆弱性
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











