BEM是用于HTML class命名的语义化约定,解决多人协作中组件归属、复用性与状态识别问题;它通过block__element--modifier格式明确结构关系与状态,要求命名与DOM层级严格对应,不参与渲染但提升可维护性。

什么是BEM,它在HTML里到底管什么用
BEM(Block Element Modifier)不是HTML标准,而是一套命名约定,用来让class名自带结构语义。它解决的核心问题是:当一个页面有几十个嵌套
class="header"根本不知道这个header属于哪个模块、能不能复用、改了会不会影响其他地方。
它的作用不在渲染,而在协作和维护——尤其当你和后端共用模板、或组件被多个项目引用时,block__element--modifier这种格式能立刻回答“这是谁的子元素?处于什么状态?”
HTML中写BEM的三个硬规则
很多人一上来就套格式,结果写出class="card__title card__title--large"却忘了父容器必须是card,导致样式失效。BEM生效的前提是结构与命名严格对应:
- 每个
__element必须直接位于对应block内部(不能跨层,不能靠CSS选择器“猜”层级) -
--modifier永远附加在block或element上,不单独存在(没有class="--disabled"这种写法) - 同一个DOM节点可以同时有block、element、modifier,但不能混用不同block的element(比如
class="button__icon card__title"就是反模式)
常见翻车现场:Vue/React里怎么写BEM才不崩
框架组件化后,BEM容易被写成“看起来像但逻辑断掉”的样子。典型错误:
立即学习“前端免费学习笔记(深入)”;
❌ 错误:在Vue单文件组件里把block名硬编码进template,但父组件传入的prop变了,class没同步更新
✅ 正确做法是把BEM生成逻辑收口到计算属性或工具函数里:
computed: {
buttonClass() {
return [
'button',
this.size ? `button--${this.size}` : '',
this.loading ? 'button--loading' : ''
];
}
}
React同理,别手写className="button button--primary",用clsx或模板字符串动态拼接。否则一旦加个isDisabled状态,就得手动补4处class。
要不要给所有元素都套BEM?什么时候该停手
BEM不是越多越好。以下情况强行套反而增加认知负担:
- 纯布局容器:比如
<div class="grid"><div class="grid__item">——如果grid只在当前页面用1次,且不带任何交互状态,用class="grid-item"更轻量 - 第三方UI库组件:给
<AntdButton>外层包一层myform__submit-button意义不大,优先用库自身的class体系+局部覆盖 - 内联SVG或图标字体:这些本就不该承担BEM语义,
class="icon icon--user"足够,不必硬凑header__icon--user
真正需要BEM的,是那些会被复用、会变状态、会和其他模块组合的业务组件——比如商品卡片、筛选表单、用户头像组。它们的名字得让人一眼看出“这是什么,能干啥,现在啥状态”。其余的,够用就行。



















