BEM是通过命名结构划定组件边界、切断隐式样式依赖的工程控制手段,用.card__title替代.card .title实现作用域隔离,避免全局污染和DOM结构变动导致的样式失效。

BEM 不是“增强 CSS 表达力”的语法糖,而是用命名结构强行划定组件边界、切断隐式样式依赖的工程控制手段。
它解决的是「改一个 .button,为什么侧边栏的 .button 也崩了」这类协作事故
根本原因在于 CSS 全局作用域 + 后代选择器(如 .card .title)把样式控制权交给了 HTML 结构。DOM 层级一变、父级 class 一换,样式就失效;更糟的是,所有带 .title 的元素都暴露在风险中。
而 BEM 强制用 .card__title 替代,把“属于 card 的 title”这个语义直接编码进类名——浏览器只做字符串匹配,不认父子关系,自然不会跨块污染。
- 错误写法:
.header .logo→ 后来加了.sidebar .logo,两个 logo 样式互相覆盖 - 正确做法:
.header__logo和.sidebar__logo各自声明,哪怕样式完全一样
BEM 的实际落地难点不在规则本身,而在团队对“边界”的松动
比如有人图快写 .user-info__name,另一处又出现 .user-name——看似相似,实则无法复用,后期维护成本翻倍。
立即学习“前端免费学习笔记(深入)”;
常见松动点:
- 混用非 BEM 类名做样式控制,如
<div class="button__text text-center">:把业务语义(<code>button__text)和通用行为(text-center)绑在同一元素上,破坏可追溯性 - Modifier 塞具体值:
button--width-200px❌,应为button--wide✅——修饰符描述意图或状态,不是视觉快照 - Element 跨 Block 命名:
card__button❌(若 button 是独立 Block),应保持边界清晰,组合时用card__action这类语义化子元素
性能影响几乎为零,但浏览器匹配效率确实更高
BEM 的性能优势不是来自名字长,而是单类名选择器一次哈希查找;而 .header .logo 这类写法会让浏览器反复向上遍历父级,DOM 越深越卡。
构建后可用 grep -r "\.[a-z]\+ \.[a-z]" dist/ 快速揪出残留的空格选择器——这是 BEM 项目里最常被忽略的“隐形债”。
最容易被忽略的是:BEM 只管名字,不管谁覆盖谁。修饰符叠加、状态类混用、CSS 文件引入顺序混乱——这些才是大型项目真正卡死的地方。


















