element不能嵌套element是bem硬性边界,禁止card__content__title等三层命名,因其破坏语义契约:将无封装能力的element误作block,导致dom微调时样式失效、无法跨上下文复用、scss嵌套生成非法类名。

Element 不能嵌套 Element,这是 BEM 的硬性边界
BEM 明确禁止 card__content__title、header__nav__link 这类三层下划线命名。它不是浏览器报错问题,而是语义契约被破坏:一旦出现第二个 __,就等于把前一个 Element(如 card__content)误当作 Block,但 card__content 本身只是 card 的直属组成部分,没有封装能力,也不具备独立复用价值。
这种写法会导致三个实际后果:
- DOM 结构微调后样式静默失效——比如给
card__content外层加个 wrapper<div class="wrapper">,<code>card__content__title就完全不匹配了 - 无法跨上下文复用——你没法把这个类名拎到弹窗、侧边栏或用户页里单独使用,它被当前 DOM 路径锁死
- SCSS 嵌套中写
&__content { &__title { } }会编译出非法类名,还容易误给card__content加 padding,违背 Element “纯展示、无布局职责” 的设计原则 - 有复用性(比如标题在卡片、弹窗、列表项都出现)→ 升为独立 Block:
heading,再组合使用:<div class="card__header"><heading class="heading--in-card">...</heading></div> - 无复用、仅装饰(如按钮旁的小图标)→ 用 Modifier:
btn__icon btn__icon--loading - 强上下文依赖、一次性场景(如折叠面板里的二级标题)→ 用 State 类:
<h3 class="heading is-subheading"></h3>或data-context="accordion" -
@at-root #{&}__header:强制提级,确保输出.card__header - 手动写全名:
.card__header:彻底绕过嵌套歧义,最可控 - 那个中间层(比如
content)是不是只是个无语义的 wrapper<div>?如果是,直接删掉,让子节点挂到 Block 下 <li>它有没有独立逻辑、样式、JS 行为?有 → 提为 Block;没有 → 不配拥有自己的下划线</li> <li>你写的 <code>card__content__title,能否脱离card__content独立存在?不能 → 它就不该是 content 的 element,而应是 card 的 element:card__title
遇到“元素里的内容”,该升块、加 Modifier,还是用 State?
关键判断标准只有一个:这个 UI 片段会不会在别处复用?
常见处理方式:
Sass 中 &__element 嵌套为什么危险?
& 在 Sass 中只是字符串拼接,空格会被原样保留。写 .card { &__header { } } 看似省事,但 VS Code 自动补全、复制粘贴带不可见字符等场景,极易变成 .card { & __header { } }(注意中间多了一个空格),结果编译出 .card .card__header —— 后代选择器,破坏 BEM 扁平化前提。
真正安全的写法只有两种:
怎么一眼识别 Element 命名是否越界?
看到类名里有 __ 出现两次,基本就能判定结构设计过深。此时不要纠结“怎么让三层合法”,而应回头问三个问题:
最常被忽略的一点:BEM 禁止的是类名嵌套,不是 DOM 嵌套。HTML 可以套五层 <div>,只要每个节点的类名归属清晰、不滑动,就完全合规。</div>











