bem类名清晰与否取决于block是否真正独立、语义能否脱离上下文理解;block必须是功能完整、可单独存在、语义明确的单元,如.search-form、.user-card,而非.wrapper、.section-2等无业务语义的容器。

直接说结论:BEM类名清晰与否,不取决于你写没写__或--,而取决于块(Block)是否真正独立、语义是否可脱离上下文理解。
怎么判断一个名字能不能当 Block?
Block 不是“随便套个 div 就叫 card”,它得是一个功能完整、能单独存在、别人一眼看懂用途的单元。
- ✅ 合规:
.search-form(有明确输入+提交行为)、.user-card(头像+昵称+操作按钮组合) - ❌ 违规:
.wrapper(纯布局容器,换页就失效)、.section-2(靠位置编号,无语义)、.top-banner(含位置描述,应拆成.banner+.banner--top) - Block 名必须全小写、短横线分隔:
.nav-menu✅,.NavMenu❌ - 删掉这个 Block,里面所有
__元素都失去意义——才说明它是真 Block。比如.profile-card__avatar拆出来单独用就怪怪的,那它依附合理;但.logo在 header、footer、modal 里样式一致,它自己就是 Block,不该写成.header__logo
Element 名为什么不能嵌套?
因为 __ 表达的是“直系组成部分”,不是“任意后代”。嵌套会模糊责任边界,让类名变成路径而非语义。
- ❌ 错误:
.card__header__title__link—— 这不是 BEM,是 selector 路径硬编码 - ✅ 正确:
.card__header+.card__title+.card__action-link(每个都是 card 的直接子语义) - 元素名不能脱离块单独使用:HTML 中必须同时出现
class="card"和class="card__title",否则 DevTools 里看到card__title_abc123根本无法反推上下文 - 如果某个“子元素”在多个 Block 里复用(比如图标),它大概率该是独立 Block:
.icon,而不是.button__icon或.card__icon
Modifier 写错最常导致全局污染
修饰符不是“换个颜色”或“调个大小”的快捷方式,它是状态标识。写错会把视觉逻辑和语义逻辑搅在一起。
- ❌ 危险:
.button--blue、.card--large—— 颜色/尺寸应由主题变量或 utility class 控制,BEM 只管状态 - ✅ 安全:
.button--disabled、.card--expanded、.input--error(布尔型);.button--size-large(键值型,且 size 是业务维度) - 修饰符只能挂载在 Block 或 Element 上:
.button--primary✅,.button__text--primary❌(除非文字颜色确实有独立状态) - 多个 Modifier 可共存,但需正交:
.button--primary--loading合理;.button--primary--secondary矛盾,说明命名没想清状态维度
CSS Modules 下 BEM 容易被忽略的关键点
开了 CSS Modules 不等于自动模块化。哈希后类名变短了,但人看不懂,协作成本反而上升。
- 必须保留 BEM 原始命名:
.card__header写进Card.module.css,编译后是card__header_xyz789,DevTools 里仍能快速定位源文件 - 禁止在 JSX 里拼接哈希后的类名:
className="card__header_xyz789"—— 这等于放弃 CSS Modules 的可维护性 - 用
clsx动态组合:className={clsx(styles.card, hasShadow && styles['card--shadow'])} - Grid 布局中,每个
grid-area对应的元素必须带完整 BEM 类名:.dashboard__header,不能只靠grid-area: header隐式绑定
最常被跳过的动作是:写完一个新 Block,没问一句“它删掉后,里面的 __ 元素还有没有独立意义?”——这一句不问,BEM 就退化成加长版 class 名。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











