BEM 的 block__element--modifier 结构不可乱改,因其核心是保障样式作用域解耦与 DOM 重构低风险:双下划线标识强归属,短横线修饰符必须依附主体,违反则破坏语义层级、导致冲突或失效。

为什么 BEM 的 block__element--modifier 结构不能乱改
BEM 不是命名“风格”,而是为了解耦样式作用域和 DOM 变更成本。一旦把 __ 写成 - 或删掉双下划线,CSS 选择器就失去语义层级,.btn-primary 和 .btn__primary 在组件重构时表现完全不同。
-
block__element表示强归属关系:这个element只在block内部有意义,移出去就失效 -
--modifier必须作用于block或element本身,不能单独存在,否则无法通过 class 切换状态 - 用
btn-large替代btn--large会导致和btn__icon--large冲突,失去修饰目标锚点
HTML 中怎么写才不破坏 BEM 语义
关键不是“有没有双下划线”,而是 class 是否真实反映 DOM 结构层级。BEM 要求每个 class 只表达一个角色:要么是 block,要么是它的 element,要么是它的 modifier。
- 禁止嵌套 block:
<div class="card"><div class="button">…</div></div>——button是独立 block,不是card的 part - element 必须直属于 block:
<div class="card"><div class="card__header"><h3 class="card__title"></h3></div></div>✅;<h3 class="card__header__title">❌(不存在__header__这种三级) - modifier 永远附加在主体 class 后:
class="card card--featured"或class="card__body card__body--compact",不能写成card-featured__body
遇到第三方组件库(如 Ant Design)怎么兼容 BEM
不要强行给第三方 class 改名或加 BEM 前缀。它们的 class 是封装好的实现细节,硬套 BEM 只会让维护更糟。
- 用 wrapper 元素隔离:
<div class="my-form"><AntdSelect className="my-form__select" /></div>,只对 wrapper 应用 BEM - 覆盖样式时用 BEM 规则写 CSS,但 selector 目标仍是第三方 class:
.my-form .ant-select-selector { … },而非试图重写.ant-select-selector为.my-form__select - 如果必须复刻 UI,就新建纯 BEM 组件,别在第三方 class 上叠 layer
什么时候该放弃 BEM,而不是硬套
BEM 在中大型项目里降低协作成本,但它不是银弹。当出现这些信号,说明当前场景不适合:
立即学习“前端免费学习笔记(深入)”;
- 组件粒度极小且无复用(比如一页只有一个
hero-banner),加hero-banner__title反而增加认知负担 - 使用 CSS-in-JS(如 styled-components),天然靠 JS 作用域隔离,
const Title = styled.h1已隐含归属关系 - 团队已稳定使用其他约定(如 SUIT CSS),强行切换带来的沟通成本 > 命名混乱成本
真正难的不是记住 __ 和 --,而是每次加 class 前问一句:这个 class 是为了让人一眼看懂结构,还是为了方便 grep 替换?后者往往埋雷。


















