BEM是大型项目CSS规范的底线,通过Block唯一语义化、Element单层嵌套、Modifier双连字符及机器可读类名,解决命名空间污染与样式冲突问题。

直接上结论:大型项目里,不强制用 BEM 就等于默认接受样式冲突、改一处崩三处、新人三天看不懂组件归属——这不是夸张,是审查元素时看到 .button 被七个文件同时定义后的日常。
为什么 BEM 是大型项目 CSS 规范的底线
BEM 不是“可选风格”,而是解决命名空间污染的最小可行方案。当项目中存在 header、button、card 这类高频通用词时,纯靠选择器权重或加载顺序来保样式生效,本质是在赌运气。
- Block 必须语义化且唯一:
search-form合法,form不合法(太泛,无法隔离) - Element 只允许一层嵌套:
search-form__input合法,search-form__header__title违规(破坏作用域边界) - Modifier 必须双连字符:
button--disabled合法,button-disabled会和 Element 命名混淆,导致 JS 操作类名时出错 - 所有类名必须机器可读:不追求人眼省力,而要让
el.classList.add('user-card__body--expanded')这种写法能被 IDE 自动补全、被 Stylelint 检查、被搜索工具精准定位
怎么避免 BEM 写着写着就变形
常见错误不是不会写,而是动态场景下松懈:JS 拼接类名、Sass 循环生成、模板里硬编码短名。这些地方最容易漏掉下划线或错用连字符。
- JS 中禁止字符串拼接:
el.classList.add('card__body' + '--' + state)→ 改为显式写全:el.classList.add('card__body--expanded') - Sass 中用
@function封装生成逻辑,而不是靠@each直接输出:@function bem($block, $element: null, $modifier: null) { ... } - 模板里禁用简写类名:Vue/React 中不要写
:class="['button', isPrimary ? 'primary' : '']",而应统一用'button--primary'或'button--secondary' - 用 Stylelint 配置
selector-bem-pattern规则,自动报错.btn-primary这类非 BEM 写法
要不要把现有项目全量迁移到 BEM
不要。全量重命名成本高、风险大、收益滞后。BEM 的价值在新增和重构环节,不是考古现场。
- 新组件一律用 BEM:从下一个
user-profile-card开始,不妥协 - 老组件只在动到样式层时渐进替换:比如修一个
.modal .close的 z-index 问题,顺手改成modal__close和modal__close--small - 保留旧类名作兼容层(仅限必要):
.old-button→.old-button.button,CSS 中写.old-button.button { ... },过渡期后删掉.old-button - 用 PostCSS 插件如
postcss-bem辅助生成,但别依赖它替代人工判断 Block 边界
真正难的不是记住双下划线和双连字符,而是每次写类名前问一句:这个东西到底属于谁?它有没有可能被另一个模块悄悄覆盖?一旦开始这么想,BEM 就不再是格式要求,而是条件反射。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











