BEM要求严格使用单一类名以保障作用域隔离与样式可预测性;禁止空格、标签、ID及嵌套选择器,Modifier须与基础类共存,第三方组件需用wrapper限定作用域。

因为单一类名是BEM能守住作用域、避免特异性失控、保证样式可预测的唯一前提——一旦加空格、标签或ID,0-1-0就破功,后续所有隔离、复用、调试优势全部归零。
为什么 .header__logo 有效,而 .header .header__logo 是危险信号
浏览器匹配 .header__logo 是一次哈希查找;匹配 .header .header__logo 则必须从右往左回溯父节点,DOM越深越慢。更关键的是,后者特异性升为0-2-0,且把样式绑死在DOM结构上:只要中间加个 wrapper,样式就静默失效。真实项目里,这类选择器往往藏在 SCSS 嵌套中,比如写 .header { &__logo { } } 是安全的,但写 .header { & .header__logo { } } 就悄悄编译出了带空格的选择器。
为什么禁止 button.header__logo 这类标签+类组合
这类写法看似“加强语义”,实则破坏 BEM 的模块边界:
- 换框架时,
button可能变成span或自定义组件,样式直接断链 - 特异性升到0-2-0,和纯类名规则形成权重竞争,覆盖逻辑不可控
- 审查元素时看到
button.header__logo,你无法判断这是设计意图还是手误
真正该做的,是在 HTML 中明确使用语义化标签,CSS 里只管样式——.header__logo 本身已声明归属与角色,不需要再靠标签“佐证”。
立即学习“前端免费学习笔记(深入)”;
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
Modifier 必须和基础类共存,button--primary 单独用会崩
常见错误是只写 class="button--primary",漏掉 button 基础类。结果是:
-
button--primary本身没定义尺寸、边框、字体等基础样式,渲染出的按钮可能只剩颜色 - 构建后类名哈希(如
button_a1b2c3)若未同步注入修饰符,整个状态就丢失 - 测试脚本用
querySelector('.button--primary')匹配,可能误判组件状态
正确写法永远是 class="button button--primary",让基础类兜底,Modifier 只负责增量变更。
第三方组件嵌入时,.my-form-field .ant-input 不是妥协,而是必要防御
遇到 Ant Design、Element Plus 这类库,不能改它们的类名,但可以划清责任线:
- 用 wrapper Block 包裹:
<div class="my-form-field"><DatePicker /></div> - CSS 写
.my-form-field .ant-input,虽特异性升为0-2-0,但作用域被严格锁在my-form-field内部 - 禁用
!important覆盖第三方样式——它会打断 BEM 的 Modifier 覆盖链,导致button--disabled在某些上下文中突然不生效
真正难防的从来不是特异性,而是类名漏写基础块、构建后哈希不一致、或 JS 拼接字符串时少打一个下划线——这些细节不靠工具链盯死,BEM 的 0-1-0 就只是幻觉。

















