bem规范要求block是独立可复用的功能单元,命名须具业务语义;element必须依附block存在且禁止嵌套;modifier描述状态或变体,需用语义化词汇而非具体值;类名须完整静态声明,禁止js拼接与后代选择器。

Block必须是独立可复用的功能单元,不是视觉分组
Block 是 BEM 的根,它得能单独存在、被复用,且有明确职责。比如 search-form、user-card、nav-menu 都合格;而 section-2、left-sidebar、header-nav 就不合格——它们要么带位置描述,要么只是临时视觉容器,没有业务语义和复用价值。
常见错误是把 HTML 标签名直接当 Block:写 div、section、header 作类名前缀。这等于放弃作用域隔离,header__logo 和 footer__logo 看似不同,但一旦抽离成独立组件,就无法保证样式不冲突。
实操建议:
- 每个 Block 对应一个可独立交付的 UI 功能(如登录表单、商品卡片、筛选面板)
- 命名用 kebab-case,全小写,不含数字或特殊字符
- 在 React 组件里统一定义常量,如
const BLOCK = 'product-card',后续所有类名都基于它生成
Element 必须依附 Block 存在,禁止嵌套 Element
Element 是 Block 的组成部分,不可单独使用。命名必须是 block__element 形式,中间双下划线 __ 是强制分隔符,不能省略或替换成 - 或 _。
典型错误包括:card__title__icon(嵌套 Element)、card-title(缺双下划线)、card__card-title(冗余 Block 名)。这些都会破坏 BEM 的层级约束,导致样式耦合加重。
遇到“元素里的子元素”,优先判断它是否具备独立语义或复用可能:
- 如果只是装饰性图标(如标题左侧小箭头),用修饰符更合适:
card__title card__title--with-arrow - 如果它是状态徽标(如“已认证”“VIP”),应升格为独立 Block:
badge,再组合使用:card__title <badge badge--type="vip"></badge> - SCSS 中只允许单层嵌套:
.card { &__title {} &__content {} },禁止出现&__title &__icon(空格会生成后代选择器)
Modifier 描述状态或变体,不能绑定具体值
Modifier 是用来表达 Block 或 Element 的外观、行为、状态变化的,命名必须是 block--modifier 或 block__element--modifier,双连字符 -- 不可替换。
错误写法:button--red(颜色值易随主题变更)、card--v2(无意义版本号)、input--width-300px(绑定具体尺寸)。这类命名会让维护变成全局搜索替换,违背 BEM 的语义化初衷。
正确方向是用可预测、可枚举的语义词:
- 状态类:
button--disabled、card--expanded、input-field--error - 变体类:
button--primary、card--compact、menu--horizontal - Modifier 必须与 Block 或 Element 并列使用,不能替代它本身:
card__title--warning合法,但card__title-warning(少一个--)或card__title warning(空格)都不合法
BEM 类名必须完整出现在 HTML 中,不能靠 JS 拼接或动态生成
很多人在 React 里写 className={`card__header ${isExpanded ? 'card__header--expanded' : ''}`>,语法没错,但问题在于 Modifier 状态逻辑散落在 JSX 多处,加个新状态就得补一串三元,很快失控。
更严重的是,如果组件内部用 header 当 Block 名,外部传入 card__header,最终生成的类名对不上,BEM 的作用域隔离就失效了。
实操建议:
- 用
classnames库收敛状态逻辑:classNames(`${BLOCK}__header`, { [`${BLOCK}__header--expanded`]: isExpanded }) - 所有 Block 名统一定义在组件顶部,避免硬编码字符串
- 禁止在 CSS 中写后代选择器(如
.card .header),BEM 的样式隔离完全依赖类名前缀,不是 DOM 层级
最常被忽略的一点:BEM 不是命名格式规范,而是组件边界契约。类名写错,往往意味着结构设计本身就有问题——比如该拆成新 Block 的强行塞进 Element,或者该用 Modifier 控制的状态却靠 JS 切换整个类名。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











