BEM推荐用于大型团队协作,因其将CSS隐性冲突显性化、可约束、可检查;通过块名前缀隔离样式、禁用嵌套选择器、强制语义化命名及自动化校验,解决类名无上下文、无所有权、无状态标识问题。

大型团队推荐BEM,不是因为它“高级”,而是它把 CSS 协作中那些隐性冲突显性化、可约束、可检查——比如两个人同时改 .btn,没人知道谁的样式会赢;但换成 .user-profile__submit-btn--disabled,冲突概率直接归零。
为什么 .logo 这种类名在协作中必然出问题
常见错误现象:div.logo 被全局重置样式覆盖;某人加了 .logo img { width: 100% },结果首页和弹窗里的 logo 全变形;审查元素发现样式来自 reset.css、header.scss、modal.scss 三个地方。
根本原因:类名无上下文、无所有权、无状态标识。它不回答三个关键问题——这个 logo 属于哪个功能模块?是哪个组件的一部分?当前是什么状态(比如暗色模式、加载中)?
- BEM 强制用块名打头,
.header__logo和.article__logo天然隔离,哪怕共用同一份 HTML 标签结构 - 禁止
.header .logo这类嵌套选择器,避免因 DOM 结构微调导致样式失效 - 所有类名必须业务语义化,禁用
wrap、container、box等泛词——因为它们无法回答“这是谁的 wrap?”
block__element--modifier 不是命名规则,是接口契约
在 React 或 Vue 组件里,block__element--modifier 实际上定义了组件对外暴露的“样式 API”。
立即学习“前端免费学习笔记(深入)”;
使用场景:一个 UserCard 组件要支持 loading、error、featured 三种状态,且内部有头像、昵称、操作按钮:
- 根元素类名必须是
user-card,不是card或profile-card - 子元素统一前缀
user-card__avatar、user-card__name,不写user-card__content__name(BEM 禁止双下划线嵌套) - 修饰符通过 props 拼接:
className={`user-card${isLoading ? ' user-card--loading' : ''}`}
这样做的效果:组件使用者只看类名就能判断样式归属,CSS 开发者不用翻 JS 逻辑就知道哪些类名可安全复用或覆盖。
CI 阶段用 stylelint-selector-bem-pattern 拦截非 BEM 写法
光靠约定没法落地。真实项目里最有效的约束是自动化检查。
性能影响:BEM 类名略长,但现代浏览器解析无感知;真正拖慢的是维护成本——没有 BEM 时,查一个样式来源平均要开 5 个文件。
- 在
.stylelintrc中启用插件:stylelint-selector-bem-pattern - 配置项强制校验:
.header .logo、.btn-primary、.card-image全部报错 - 配合 VS Code 插件
BEM Tools,输入btn__text回车自动补全为button__text - 建立
bem.config.json约定 block 命名范围,如只允许user-、order-、payment-开头
BEM 的复杂点不在语法,而在于它要求你提前思考“这个 UI 片段是否真的能独立存在”。一个图标如果只在 ProductCard 里出现,就该叫 product-card__icon;如果它要跨组件复用,就得单独抽成 icon--search ——但这时你要警惕:100 个图标建 100 个类,反而让样式表膨胀失控。BEM 是工具,不是教条。


















