BEM是组件结构约束而非字符串模板,block须为带业务含义的独立单元(如user-card),禁用泛标签名;element仅属单一block,modifier仅表状态且平级组合。

什么是BEM,为什么直接套用block__element--modifier会出问题
因为BEM不是字符串模板,而是组件结构约束。你写header__logo--dark没问题,但若页面里有多个header(比如main-header和modal-header),它们的__logo语义就冲突了——BEM要求block必须是独立、可复用的最小样式单元,不能是泛指的HTML标签或模糊容器名。
常见错误现象:div.header > div.logo被硬套成header__logo,结果在另一个模块里复用logo时,样式被header__logo意外污染。
- 真正有效的
block名应带业务含义,比如user-card、search-form,而非header、section -
__element只能属于且仅属于一个block,禁止跨block嵌套命名(如user-card__avatar__icon是错的,应为user-card__avatar-icon) -
--modifier不改变结构,只开关状态,所以不能用来表达层级关系(button--primary-large可以,button--in-modal不行)
从一个按钮组件开始写对BEM类名
拿最简单的Button举例:它要支持主题(primary / secondary)、尺寸(small / large)、加载态。这时候类名不是凭空编的,而是由组件API反推出来的。
使用场景:React中你可能会写<button variant="primary" size="large" loading></button>,对应CSS类就该严格对齐这个接口。
立即学习“前端免费学习笔记(深入)”;
- 基础块名用
btn(短、无歧义、行业通用),不是button(太泛,易和原生button标签混淆) - 主题用
btn--primary,不用btn-primary(后者不符合BEM双横线约定,也难区分modifier和element) - 尺寸和状态叠加时,顺序按“类型→状态”排:
btn--large btn--loading,而不是btn--loading-large(modifier之间无层级,应平级组合) - 如果按钮内有图标,命名为
btn__icon,不是btn-icon(后者会被误判为另一个block)
示例结构:
.btn { }
.btn--primary { }
.btn--large { }
.btn--loading { }
.btn__icon { }
遇到嵌套组件时,BEM怎么避免类名爆炸
比如user-card里有个avatar,而avatar本身又是独立可复用组件。这时候不能写user-card__avatar__image,也不能把avatar整个CSS搬进去。
正确做法是让avatar保持完整block身份,在user-card里只做组合调用:
-
user-card内部用<div class="avatar">,而不是<code><div class="user-card__avatar"> <li>需要微调样式时,用<code>user-card .avatar局部覆盖,或加一层user-card__avatar-wrapper作为布局钩子 - 绝对不要为了“看起来统一”把所有子组件都降级为
__element——那等于放弃组件复用能力 - 工具链上可用
postcss-bem自动补全前缀,但别依赖它生成逻辑;BEM结构必须人工确认
CSS-in-JS或Tailwind项目还用BEM吗
用,但角色变了。BEM不再主导选择器组织,而是作为命名契约存在。
在styled-components里,你可以这样写:
const Button = styled.button`
&.btn--primary { background: blue; }
&.btn--large { padding: 12px 24px; }
`;
这时btn--primary不是CSS类名,而是传给组件的className值,作用是触发对应样式分支。关键点在于:即使不用CSS文件,btn、btn--primary这些字符串仍需在JSX、测试、文档里一致出现。
- Tailwind项目中,BEM转为class命名规范:用
btn作前缀分组,如btn-primary、btn-lg,虽不严格符合BEM语法,但保留了语义分层意图 - 容易被忽略的是:BEM的真正价值不在CSS选择器,而在团队沟通时能说清“这个
user-card__content是user-card的直属内容区,不包含footer”——这种结构共识比语法细节重要得多
复杂点从来不在规则多,而在每次加新class前,是否真想清楚了它属于哪个block、有没有泄露内部结构、会不会被别处误用。


















