Element不能嵌套Element,BEM明确禁止如.header__nav__item或.card__body__list__item这类三层命名,因Element必须直接隶属于Block,三层下划线表明UI单元职责不清,应拆分为独立Block或用Modifier表达状态。

Element不能嵌套Element,这是BEM最常被踩的红线
写 .header__nav__item 或 .card__body__list__item 是错的——BEM 不允许元素再包含元素。双下划线 __ 只能出现在块名之后,且只隔一层。一旦出现三层及以上下划线,说明你把本该独立的 UI 单元强行塞进了父级结构里。
常见错误现象:
-
.user-card__avatar__upload-btn:avatar 和 upload-btn 都是可复用单元,不该绑定在 user-card 内部命名 -
.form__field__label:label 是 field 的直接子元素,但若 label 本身有图标、辅助文本等子结构,应提取为独立 Block(如.label-icon)而非继续拼接
判断标准很简单:这个 UI 片段会不会在别处复用?有没有自己的样式边界或交互逻辑?如果有,它就该是一个 Block,而不是某个块的“孙子元素”。
Element必须直接属于Block,且语义要单一明确
Element 是 Block 的**直接组成部分**,不是 DOM 树上的任意后代节点。比如 .card__title 合理,因为 title 是 card 的核心内容之一;但 .card__footer__copyright 就越界了——footer 本身已是具备结构和复用潜力的单元,应定义为独立 Block:.footer,其内部再定义 .footer__copyright。
立即学习“前端免费学习笔记(深入)”;
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
实操建议:
- HTML 中每个 Element 对应一个 class,且只带一个
__结构,如class="card__title",不写class="card__body__title" - Element 名称用名词,描述角色而非位置,
.card__image✅,.card__top-image❌(位置信息应由 Modifier 或布局控制) - 避免用动词或模糊词:
.card__show-more应改为.card__action+.card__action--expand
当需要表达“某元素在特定上下文中的变体”,改用 Modifier 而非深层 Element
比如按钮在卡片内需缩小尺寸,不要写 .card__body__button,而应让 button 是独立 Block,然后加修饰符:class="button button--in-card"。这样既保持 Block 独立性,CSS 选择器也更可控、不易被意外覆盖。
关键点:
- Modifier 名称聚焦行为或状态,
--in-card✅,--inside-header❌(后者是位置依赖,不可移植) - 修饰符可作用于 Block 或 Element,但必须紧接其后:
.button--loading、.card__button--disabled都合法;.card__button--loading--disabled❌(不允许连写两个--) - 多个 Modifier 平级共存:
class="button button--primary button--loading",靠组合选择器控制复合样式
工具链能帮你守住这条线,但前提是你不手动绕过
纯靠人肉约定容易漏写 __ 或多加空格。Webpack + postcss-bem 允许你写 .card { &__title {} &--hovered {} },自动编译成真实类名;CSS Modules 下用 styles.title 和 styles.titleDisabled 也能自然隔离层级。
真正容易被忽略的是:BEM 的扁平化不是靠“少写几层下划线”实现的,而是靠对 UI 单元职责的持续审视——每次想加第三个 __,先问一句:“这个东西,真的离不开它上面那个块吗?”

















