BEM类名通过三段式结构(Block__Element--Modifier)明确归属、角色与状态,避免语义模糊和隐式嵌套,强制每个元素仅用一个BEM类,提升可读性与可维护性。

因为 BEM 类名本身就能回答「这是谁的、是什么、当前什么状态」三个问题,不用翻 HTML、不依赖注释、不靠口头对齐。
类名直接暴露组件结构和上下文
传统命名如 .title 或 .red 没有归属信息,你得点开 HTML 才能确认它属于哪个模块;而 product-card__title--warning 一眼可知:它是 product-card 这个块里的标题元素,且处于 warning 状态。
浏览器不关心语义,但人眼扫过去就自动还原出结构关系。这种“秒懂”能力来自三段式结构强制绑定:
-
product-card是 Block —— 表明它是独立功能单元,不是泛义容器 -
__title是 Element —— 表明它是该 Block 的语义化组成部分,不是__el-1或__content这种模糊筐名 -
--warning是 Modifier —— 表明这是可枚举的状态变体,不是临时加的样式补丁
Element 命名不准,自解释性立刻归零
常见错误是把行为或样式塞进 Element 名,比如 user-card__delete-btn:
立即学习“前端免费学习笔记(深入)”;
-
delete是行为动词,锁死在“删除”场景,后续复用为“取消关注”就语义失真 -
btn是样式词,万一改成图标或文字链接,类名就彻底失效 - 正确写法是
user-card__action--delete:Action 是稳定角色,delete 是可枚举状态,二者解耦
更隐蔽的问题是泛化命名:card__content 看似合理,但 content 是个筐,别人无法判断它到底管图片、描述还是按钮。应按实际角色命名:card__image、card__body、card__footer。
BEM 不禁止伪类和媒体查询,但禁止隐式嵌套
很多人误以为 BEM 就是“不能写 .button:hover”,其实不是:
- ✅ 允许:
.button:hover、.button--disabled:focus、@media (min-width: 768px) { .card__title--large { ... } } - ❌ 禁止:
.button { &:hover { ... } }(Sass 嵌套生成后代选择器)、.button .button__label(用空格依赖 DOM 层级)
真正危险的是预处理器里偷偷破坏结构:.card { &__header.is-open { } } 编译成 .card__header.is-open,Modifier 错绑到 Element 上,违反 BEM 铁律——Modifier 应作用于 Block 或 Element 自身,不能跨层修饰。
每个 HTML 元素只允许一个 BEM class
这是最容易被忽略的硬约束。比如给按钮同时加 button__text 和 text-center,后者是全局工具类,混用会让团队无法分辨哪些 class 是业务逻辑主干、哪些是临时补丁。
真实项目里,多一个非 BEM class 就可能引入歧义。调试时在 DevTools 的 Computed Styles 里一眼就能验证:.card__title--large 如果带空格或混入 [data-],基本就是写错了。
真正难的从来不是记住 __ 和 -- 的写法,而是每次加新类名时,多问一句:“这个类脱离当前文件,别人能看懂它属于谁、起什么作用吗?”


















