card__header__title是非法命名,因BEM明确禁止元素嵌套元素,所有__element必须直接隶属于Block,否则破坏语义隔离、复用性与工具链校验。

为什么 card__header__title 是非法命名
BEM 明确禁止元素嵌套元素,card__header__title 看似结构清晰,实则破坏了 BEM 的语义根基:它让 title 依赖于 header 这个中间层,而 header 本身只是 card 的一个 __element,不具备独立作用域。BEM 要求所有 __element 必须**直接隶属于 Block**,否则就无法保证该类名在别处复用时样式稳定。
常见错误现象:
- 开发者看到 DOM 嵌套深(
<div class="card"><div class="card__header"><h2 class="card__header__title">),就机械照抄 HTML 层级生成类名 - 用 Sass 多层嵌套(如
.card { .card__header { .title { ... } } })编译出card__header__title,结果这个类名既不能独立测试,也无法抽离为通用组件
__element 必须语义上属于 Block 本身
所谓“孙子”,在 UI 逻辑中往往不是真正的子元素,而是另一个可复用的单元。比如 card__header__title 中的 title,实际语义是“卡片头部的标题”,但它的样式和行为并不绑定于 header——它可能出现在弹窗头部、侧边栏头部、甚至独立页面顶部。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 把
title提升为独立 Block:heading或section-title,定义heading__text和heading--level-2 - 若必须表达位置关系,用父级类名控制样式,例如:
.card__header .heading(注意:这不是 BEM 选择器,而是安全的上下文限定) - 在 React/Vue 中,通过
classNameprop 注入 context 类(如heading--in-card),避免硬编码嵌套名
强行写三层命名会引发哪些实际问题
表面上只是多两个下划线,实际会触发一连串工程副作用:
- CSS 选择器权重失衡:
.card__header__title权重等同于.card .card__header .title,远高于扁平的.card__title,容易意外覆盖或被覆盖 - 类名爆炸:一旦
header内还要加icon、subtitle、badge,就会衍生出card__header__icon、card__header__subtitle……维护成本指数上升 - 组件抽离困难:含
__header__的类名无法单独提取为可复用模块,因为它的语义已和card强耦合 - 工具链报错:postcss-bem-linter 会直接标红
card__header__title,认为它违反element只能一级深度的规则
遇到真实嵌套 DOM 时怎么写才合规
DOM 结构可以嵌套,但 BEM 类名不能反映这种嵌套。关键判断标准只有一个:这个 UI 片段会不会在别处复用?是否拥有自己的逻辑边界?
实操路径:
- 先检查是否已有对应 Block:比如
list、button-group、badge—— 直接复用,不造新名 - 没有现成 Block 且确定只在此处使用?考虑用 Modifier 表达变体,例如:
card__title--compact(紧凑模式)、card__title--with-icon(带图标) - 需要强上下文样式(如弹窗内按钮组间距更小)?用属性选择器:
[data-context="modal"] .button-group,或在父容器加修饰符:modal--wide .button-group
真正难的不是记住“不能三层”,而是每次写类名前停半秒,问一句:它真的只属于这里吗?


















