BEM是一种通过block、element、modifier三类命名约定实现样式隔离与可维护性的CSS方法:block为独立模块(如card),element为其子部件(card__title),modifier描述状态(card--featured),强制扁平化、语义化、无嵌套依赖。

BEM 是目前最直接、最可控的 CSS 命名与结构组织方式,它不依赖预处理器或框架,纯靠命名约定就能让样式归属一目了然。
什么是 BEM 的 block、element、modifier
BEM 把 UI 拆成三类实体:block(独立功能模块,如 header、card)、element(隶属于 block 的子部件,如 card__title、card__image)、modifier(描述状态或变体,如 card--featured、button--disabled)。
关键不是“加不加双下划线”,而是强制切断嵌套联想——card__title 和 card 有明确归属关系,但和 article__title 完全无关,也不会因 DOM 层级变动而失效。
- 不允许写
.card .title这类依赖父子结构的选择器 - 不允许用
.card__title--large这种“modifier 套 modifier”,应拆成.card__title.card--large或新 block - element 名必须语义化,避免
card__left这类位置描述,改用card__avatar、card__content
如何把现有 CSS 快速转成 BEM 风格
不是重写,是“重命名 + 重构选择器”。先锁定一个组件(比如登录表单),然后逐层剥离 DOM 依赖:
立即学习“前端免费学习笔记(深入)”;
- 把
.login .input改成.login__input,删掉所有空格选择器 - 把
.login .input.error改成.login__input.login__input--error(注意:modifier 修饰的是 element,不是 block) - 移除所有
:hover、:focus等伪类直接写法,统一用--focused、--hovered类控制,便于 JS 切换和调试 - 如果某个样式只在特定页面生效(如首页的 banner),不要加
.home .banner,而是新建banner--homemodifier
为什么 BEM 能避免 CSS 冲突和覆盖问题
因为所有 class 都是扁平、唯一、带上下文的。没有全局污染,也没有隐式继承链:
-
button和form__button是两个完全独立的样式作用域,哪怕写在同一份 CSS 文件里也不会互相干扰 - 删除
card模块时,只需删掉所有含card前缀的 class 和对应样式,不会误伤其他地方的title或image - 构建工具(如 PostCSS)可轻松提取
card相关样式做按需加载,前提是 class 名具备可识别前缀 - 多人协作时,看到
search-bar__submit--loading就知道它属于 search-bar,处于 loading 状态,不需要翻 DOM 结构或查 Git 历史
BEM 在真实项目中容易被忽略的细节
真正卡住人的往往不是规则本身,而是边界情况的处理习惯:
- 第三方组件(如日期选择器)的 class 不受控?不要强行覆盖,用 wrapper block 包一层,例如
form-field--date <div class="datepicker"></div>,只对 wrapper 写样式 - 需要响应式微调?不要写
@media (min-width: 768px) { .card__title { ... } },而是新增card__title--sm并在媒体查询里开关它 - JS 绑定事件时,别用
document.querySelector('.card__button'),改用element.querySelector('[class*="card__button"]')或 data 属性(data-js="card-submit"),避免样式名和行为逻辑强耦合
越复杂的页面,越要克制“用嵌套表达层级”的本能;BEM 的价值不在写的时候省事,而在改的时候不猜、不试、不连带修复。


















