bem 通过命名约定实现样式隔离,无需构建工具、零运行时负担、浏览器原生支持;其核心是开发者主动维护 block 边界,严格遵循 block__element 和 block--modifier 结构,防止 class 冲突。

因为 BEM 不需要任何构建工具、不改变运行时行为、不增加打包体积,仅靠命名本身就把作用域边界刻进类名里——.search-form__input 一写出来,它属于谁、是什么、什么状态就全定了,浏览器原生支持,IE8 都认。
为什么不用工具也能防住 class 冲突
BEM 的隔离效果不来自哈希或属性选择器,而来自开发者每次写类名时的主动判断:“这个样式脱离 search-form 还能成立吗?”只要 block 名真实存在(如 <form class="search-form"></form>),且所有子类都严格遵循 block__element 或 block--modifier 结构,那 .search-form__input 就永远不会匹配到 Ant Design 的 ant-btn 或 Element Plus 的 el-input。
常见错误现象:
- HTML 漏加
search-form类,导致search-form__input样式静默失效(不是污染,是失效) - 手写
.search-form .input后代选择器,等于主动凿穿沙箱墙,弹窗挂到时直接失灵 - 第三方组件渲染出
class="btn",你改.btn就中招;但改.search-form__button完全不影响它
为什么比 CSS Modules / scoped 更轻量
CSS Modules 编译后生成 _button__label_abc123 这类哈希名,确实隔离了运行时冲突,但代价是 DevTools 里完全不可读;scoped 依赖 data-v-hash 属性选择器,大量 DOM 节点带属性会拖慢渲染,且外部定义的 .footer 仍能穿透进来。
BEM 没这些开销:
- 零构建成本:不用配
css-loader、不用启postcss-bem-linter,一个刚入职的前端看懂user-card__avatar--loading就知道这是用户卡片头像的加载态 - 零运行时负担:浏览器对单类名选择器(如
.user-card__avatar--loading)做一次哈希查找,比.user-card .avatar从右往左逐层回溯快得多 - 零兼容性风险:不依赖
scoped的属性选择器,也不依赖 CSS-in-JS 的 JS 注入逻辑,服务端直出 HTML 时就是唯一契约
最容易被绕开的破功点:Block 边界模糊
BEM 不是靠双下划线数量起效,而是靠 block 是否真实代表一个独立、可复用的 UI 单元。一旦边界松动,整个命名空间就塌缩:
-
header__logo是对的,但把header__logo拿去用在<aside></aside>里,就违背了 block 归属——应另建sidebar__logo - 禁止
form__field__label:Element 不能嵌套,__只表示 block 的直属子结构,多一层就语义断裂 - 修饰符必须依附 block 或 element 存在:
button--primary✅,--primary❌;button__icon--loading✅,icon--loading❌(失去 block 锚点)
真正难的不是拼对 __ 和 --,而是每次写类名前,都得确认那个元素是不是它所属 block 的固有部分——这种判断没法交给工具,只能靠人盯住。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











