深入理解 BEM 命名规范的核心要点:Block 必须是语义完整、可复用的独立组件(例如 .card),而非视觉容器(如 .section-2);Element 仅作为 Block 的直接子语义部件(比如 .card__title),禁止嵌套层级;Modifier 表达可预测的状态变化(如 .button--disabled),不绑定具体样式值。听起来简单,实际落地时很多开发者容易偏离方向,下面逐一拆解 BEM 规范的正确用法。

Block 是独立组件单元,不是视觉容器
BEM 中的 Block 必须具备可复用性、语义完整性和独立样式作用域。它不应是“随便一个 div”或“页面里第几个 section”。例如 .card 是合法命名,因为它是可复用的卡片组件;而 .section-2 或 .wrapper 则不合规——它们仅描述位置或结构,缺乏业务语义。
常见错误现象:.header__na v 看似合理,但如果导航组件在侧边栏也复用,那它就应该作为独立 .na v Block,而非 header 的子元素。
- Block 名必须小写、连字符分隔(如
search-bar),避免使用驼峰或下划线 - 不能携带父级语义:❌
.card__card-title,✅.card__title - 禁止仅依靠 DOM 层级推导 Block:即使 HTML 中
,也不应直接写.card .title—— 必须显式声明.card__title
Element 是 Block 的直接子语义部件,不嵌套
Element 描述 Block 内部的组成部分,命名应聚焦功能而非结构。它与 Block 之间只能有一层关系:Block → Element,不允许出现 Block → Element → SubElement 的层级。
常见错误现象:.card__content__title 或 .menu__item__link 这类三层命名,表明设计已超出合理范围——要么将 title 提升为独立 Block(如 .heading),要么重新审视是否真的需要如此深的语义层级。
- Element 名不应包含 Block 名前缀冗余:❌
.card__card-header,✅.card__header - 所有 Element 必须是 Block 的直接子节点(HTML 层面不强制,但语义上应视为平级关系)
- 如果某个“子元素”在多个 Block 中复用(如图标、徽标),它就应该是一个独立 Block:
.icon,而非.button__icon或.card__icon
Modifier 表达状态或变体,不绑定视觉快照
Modifier 是 Block 或 Element 的修饰,用于表达可预测的状态变化(如 is-loading)、尺寸变体(--large)或主题变体(--dark)。它不是 CSS 属性的直接翻译,而是业务意图的映射。
常见错误现象:.button--red 或 .card--big 看似直观,但换品牌色时就需要全局搜索替换;.button--primary--disabled 这种链式写法会破坏组合自由度。
- Modifier 必须依附于 Block 或 Element 存在:✅
.button--disabled、✅.button__text--small,❌ 单独使用.--disabled - 多个 Modifier 并列使用,不嵌套:✅
.button--primary.button--disabled,❌.button--primary--disabled - 值必须可维护:✅
--loading、✅--featured,❌--v2、❌--new
SCSS 嵌套中怎么守住 BEM 边界
SCSS 的 & 符号本身不违反 BEM,但稍不注意就会生成后代选择器,破坏扁平类名契约。关键在于编译后是否引入了空格。
错误示例编译出 .card__title .icon,这相当于退回到结构依赖的老路;正确写法只产出 .card__title 和 .card__title--hovered 这类扁平类名。
- 安全写法:
.card { &__title { … } &--horizontal { … } } - 危险写法:
.card { &__title { .icon { … } } }→ 编译为.card__title .icon - 真需关联子节点样式,优先用属性选择器:
[data-icon="close"],比.modal__header__close更可控
BEM 的逻辑结构并非靠语法强制,而是靠命名即契约——类名写错,往往意味着组件职责划分本身就有问题。最常被忽略的是:Modifier 不应单独存在,Element 不应有子 Element,Block 不应是“看起来像一块”的视觉分组。
