&__element 会编译出后代选择器而非扁平类名,因 & 表示完整选择器字符串且嵌套自动加空格;唯一可靠写法是 @at-root #{&}__element。

直接用 &__element 或 &--modifier 在块顶层写,看似简洁,但编译结果是 .block .block__element(带空格的后代选择器),不是 BEM 要的扁平类名 .block__element。唯一可靠方式是 @at-root 配合插值。
为什么 &__title 会编译出错误选择器
SCSS 的 & 表示“当前完整选择器字符串”,不是“块名”。在 .card { &__title { } } 中,& 确实是 .card,但嵌套机制天然加空格,结果是 .card .card__title —— 合法 CSS,但违背 BEM 单类名原则。
空格意味着样式依赖 DOM 层级:若 HTML 只写 <div class="card__title">,没包 card,样式完全不生效。
-
.card { .header { &__title { } } }→.card .header__title,语义错乱 -
.button { &:hover { &__icon { } } }→.button:hover__icon,浏览器直接忽略 -
.sidebar .widget { &__header { } }→.sidebar .widget__header,BEM 只认.widget__header
@at-root #{&}__element 是唯一安全写法
必须跳出嵌套上下文,在 CSS 根层级拼接类名。核心是 #{&} 取当前块名(不含空格),再拼 __ 或 --。
立即学习“前端免费学习笔记(深入)”;
- 正确:
.card { @at-root #{&}__header { color: #333; } }→ 输出.card__header - 修饰符同理:
@at-root #{&}--loading { opacity: 0.7; }→.card--loading - 变量也适用:
$block: "button"; @at-root #{$block}__icon { ... } - 禁止在
@media、&:focus、&[disabled]内部再用@at-root #{&}__xxx,输出顺序不可控
多层视觉结构不能靠 __ 套娃
BEM 明确禁止 block__element__subelement(如 card__header__title)。这不是语法限制,而是语义失效信号:它把 card__header 错当 Block,但它只是 Element,无法独立复用。
- 判断标准很实在:删掉
card,card__header__title还有意义吗?没意义 → 它不该是子元素的子元素 - 真实场景应拆新 Block:
comment__reply__reply→ 改为独立comment块 +comment--nested - SCSS 里写
&__header { &__title { } }不仅产出非法类名,还容易误给card__header加 padding,破坏 Element 纯展示语义 - HTML 中每个 Element 必须显式带 Block 类:
<div class="user-card"><img class="user-card__avatar"></div>,不能只写class="user-card__avatar"
真正容易被忽略的是:BEM 的解耦效果不来自 SCSS 语法糖,而来自对类名归属的强制约束。哪怕编译器输出了正确的 .card__title,如果 HTML 漏了 card 这个基础类,样式就静默失效——DOM 上少一个 class,比逻辑错误更难定位。


















