block 是能独立存在、复用、测试和配置的组件单元,具备自有样式文件、跨上下文使用、配套 js 行为;element 仅作为 block 的直接子节点存在,不可脱离 block 单独使用。

Block 和 Element 不是靠视觉大小或嵌套深浅判断的,而是看它能不能“自己活”——有独立样式、行为、复用场景,且不依赖父容器就能存在。
怎么识别一个东西该是 Block 而不是 Element
真正决定它是 Block 还是 Element 的,不是它长得多大、多复杂,而是工程中它是否具备独立存在能力:
- 删掉它的父级容器后,它还能不能单独渲染、测试、配置?能 → 就该是 Block
- 它有没有自己的 CSS 文件(比如
avatar.css),不依赖user-card.css就能生效?有 → Block - 它是否出现在至少两个无关上下文里(如用户卡片、评论区、设置页)?是 → Block
- 它有没有配套 JS 行为(如点击放大、加载状态管理),且逻辑不耦合于父组件生命周期?有 → Block
常见误判:.section-2、.wrapper、.main-content 这类纯视觉分组,没业务语义、不可复用、删了不影响其他模块,就不是 Block,只是无意义的容器。
Element 必须是 Block 的直接子节点,且不能脱离 Block 单独使用
HTML 结构必须严格对应命名层级,否则 BEM 就失效了:
-
.card__title对应的 DOM 必须是<div class="card"><h2 class="card__title"></h2></div>,中间不能插一层<div class="card__inner"> <li>如果结构上不得不加中间层(比如为了布局),那这个中间层本身就应该是一个新 Block(如 <code>.card-body),而不是用.card__inner勉强撑着 -
.card__body__paragraph是非法写法 —— BEM 不允许双下划线嵌套,它违反了“Element 只能直属于 Block”的硬约束 - SCSS 中写
&__body { &__paragraph {} }会生成.card__body__paragraph,语法合法但语义错误,得手动拆成两个 Block 或改用属性选择器 - Block 名称必须全小写、单词间只用短横线(
user-profile✅,userProfile❌,user_profile❌) - Element 名称描述“它是什么”,不是“它看起来怎样”:用
.card__close-btn✅,不用.card__red-btn❌(颜色该由 Modifier 控制) - Modifier 永远不能单独出现:
.card--featured✅,.--featured❌,.featured❌ —— 缺失锚点就失去作用域隔离 - 禁止用 HTML 标签名当 Block:
.header可以,但前提是它封装了完整功能;直接把原生<header></header>当 Block 用,一换标签就崩
命名细节决定 BEM 是否真正起作用
很多项目写了 __ 和 -- 却还是样式冲突,问题往往出在命名习惯上:
最容易被忽略的是抽象粒度:一个图标如果支持尺寸、颜色、加载态等变体,并在按钮、输入框、卡片里都复用,它就是 .icon Block,而不是任何 __icon Element。











