bem 是大型前端团队 css 可维护性的必要约束,其核心在于强制类名携带模块归属信息、禁止空格选择器以提升性能、通过工具链(如 stylelint)和目录结构规范保障落地。

因为不强制用 BEM,大型前端团队的 CSS 就不是“可能出问题”,而是“每天都在爆破式失控”——改个 padding 导致三个不相关页面按钮错位、弹窗遮罩消失、响应式断点集体失效,这不是偶然,是结构松动后的必然连锁反应。
为什么单类名选择器在浏览器里快得不可替代
BEM 的性能优势不来自名字长短,而在于浏览器匹配机制:.user-card__avatar--loading 是一次哈希查找;.user-card .avatar 则要先找所有 .avatar 元素,再逐层向上检查父级是否为 .user-card,DOM 越深越慢。
- DevTools → Computed → Styles 面板里一眼就能看出有没有空格——有空格就是潜在性能隐患
- Sass 中写
.user-card { &__avatar { } }安全;但写.user-card { & .user-card__badge { } }就会编译出带空格的选择器,破坏隔离性 - 构建后可用
grep -r "\.[a-z]\+ \.[a-z]" dist/快速揪出残留的空格选择器
为什么类名不带归属信息,协作立刻退化成猜谜游戏
当一个 .btn 被改坏,影响订单页、弹窗、侧边栏,问题往往出在没人知道它属于哪个上下文。BEM 强制类名携带“户籍信息”:checkout-form__submit--loading 一眼可知:只属于 checkout-form 模块,是 submit 元素的 loading 状态。
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
-
checkout-form__submit只命中该模块,不会误伤user-modal__submit - 禁止跨 Block 使用 Element:
user-card__avatar放进message-list容器里,就违反 BEM 原则,导致样式失效或意外继承 - 目录结构必须对齐:
/components/product-card/下的 CSS 文件里,只允许出现.product-card、.product-card__price等,出现.user-profile__avatar就说明模块边界已失焦
为什么光靠文档和口头约定,BEM 一天就形同虚设
手滑一次,比如在 SCSS 里写了 & a { color: blue; },就等于注入了全局 a 样式,和 BEM 无关。规范落地必须靠工具链“焊死”。
- 必须配置
stylelint-selector-bem-pattern插件,规则设为{ "componentName": "[a-z][a-zA-Z0-9]+", "styleType": "bem" },自动拦截.card .title、.btn-primary等非 BEM 写法 - CI 流程中跑
npx stylelint "**/*.{css,scss}",失败则阻断合并 - 禁止在 JS 中拼接字符串:
className={`card__body ${isCollapsed ? 'card__body--collapsed' : ''}`}应改为用cn('card__body', { 'card__body--collapsed': isCollapsed })
真正难的不是写出 block__element--modifier,而是让团队在加一个 tooltip 时,本能地新建 /components/tooltip/ 而不是往 modal.css 里塞 .modal__tooltip——这需要目录约束、CI 检查、以及最初几个模块的示范性实现。边界感一旦松动,BEM 就只是带下划线的普通 CSS。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










