BEM通过将样式归属写入类名确保重构安全:块名(如user-card)是基础前提,修饰符(如--loading)须与之共存;禁止层级选择器和模糊modifier命名,须描述可观察UI变化。

因为BEM把“这个样式属于谁”直接写进类名里,重构时删代码、挪结构、改状态都不会意外牵连其他模块——只要HTML里还保留user-card这个块名,所有user-card__*和user-card--*就依然生效。
重构时最常被误删的「基础块类」
很多人只记得删user-card__avatar--loading,却忘了user-card__avatar本身才是样式生效的前提。一旦HTML里只剩class="user-card__avatar--loading"而漏了user-card__avatar,整个元素就失去基础样式,控制台无报错、审查元素也看不出问题。
- 必须保证每个带修饰符的元素同时携带其基础块或元素类:
user-card__avatar user-card__avatar--loading,不能省略前者 - JS动态增删类时,别只操作
el.classList.toggle('user-card--featured'),要确认user-card始终存在 - 用
clsx或bem('user-card', { avatar: true, loading: isLoading })这类工具封装,避免手拼字符串漏前缀
移动DOM结构后样式失效?那是没写对BEM
传统写法.user-card .avatar依赖层级,一挪就断;BEM要求所有规则以单类名为根,比如.user-card__avatar。它不关心这个元素在不在user-card内部,甚至不关心它是不是div还是img——只要类名对,样式就生效。
- 检查构建后CSS:用
grep -r "\.[a-z]\+ \.[a-z]" dist/揪出带空格的选择器,它们是BEM退化的信号 - Sass中禁止写
.user-card { & .user-card__badge { } },正确是.user-card { &__badge { } } - 如果组件被抽成独立npm包,
mylib-user-card__avatar这种完整命名能天然隔离,不惧宿主项目冲突
Modifier命名不当会让回归测试完全失效
写user-card--is-loaded看似合理,但它描述的是数据状态而非UI表现。测试脚本想验证“加载态是否显示骨架屏”,结果发现--is-loaded只控制opacity,而骨架逻辑藏在另一个user-card__skeleton里——根本没法靠类名定位行为。
立即学习“前端免费学习笔记(深入)”;
- Modifier必须描述可观察的视觉或交互变化:
--loading(显示转圈)、--collapsed(高度为0)、--error(红边框+提示图标) - 禁止用
--active这种模糊词,优先用--selected或--focused明确触发条件 - 多个Modifier可共存:
user-card__header user-card__header--large user-card__header--sticky,但不能嵌套:user-card__header--large--sticky非法
真正卡住重构进度的,往往不是类名写错,而是块名和真实DOM容器脱节——比如叫product-list的块,实际HTML里只是个没加class的div,或者多个不相关区域共用同一个块名。这种隐性耦合不会报错,但会让每次搜索替换都变成雷区。


















