bem 能让组件样式“看名知意、改一处不牵连”,前提是 block 边界清晰、modifier 不越界、element 不跨块;block 名须为带业务语义的独立单元,如 user-card,禁用泛标签名(card、nav)和 html 标签名,多词用短横线连接,主题不应塞入 block 名;element 禁止嵌套命名(如 user-card__avatar__icon),须为名词且聚焦功能,图标等通用结构应抽为独立 block;modifier 必须平级叠加(btn--large btn--loading),不可作用于 element,禁用伪修饰符;与 tailwind 或 css-in-js 共存时,bem 退为思维框架,类名用于逻辑组织而非手写模板,构建工具校验依赖标准命名格式,且 bem 类名本身可作 js 选择器使用。

直接用 BEM 能把组件样式从“靠猜和覆盖”变成“看名知意、改一处不牵连”,前提是 Block 边界清晰、Modifier 不越界、Element 不跨块。
怎么定义一个组件的 Block 名称才不会后期翻车
Block 名必须是带业务语义的独立单元,不能是泛标签或模糊容器名。比如 user-card 合规,card 或 header 就容易在多个上下文里冲突。
- 禁止用 HTML 标签名当 Block:写
nav不如写main-nav或footer-nav,否则复用时样式会互相污染 - 命名要短但无歧义:
btn比button更常用也更安全,行业已有共识,且避免和原生<button></button>标签混淆 - 多词用短横线连接:
search-form✅,searchForm❌(BEM 明确要求小写+短横) - 如果组件支持主题切换(如暗色/高对比),不要把主题塞进 Block 名里:
dark-header是错的,应该用header--dark
Element 命名为什么不能嵌套再嵌套
user-card__avatar__icon 这种四层结构不是 BEM,是命名灾难。它违反了 Element 只能属于一个 Block 且不可复用的基本前提。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 元素名必须是名词,聚焦功能而非视觉:
user-card__avatar✅,user-card__avatar-img❌(img 是标签,不是语义) - 图标这类通用子结构,优先考虑抽成独立 Block:
icon icon--small,而不是硬塞进父级的 Element 层级 - 真需要上下文绑定时(比如图标颜色随卡片主题变),可用单下划线作例外:
user-card__avatar-icon,但必须全团队书面约定,不能随意滥用 - 构建工具(如
postcss-bem-linter)通常只认一级__,遇到__avatar__icon直接报Invalid BEM node
Modifier 怎么叠加才不会失控
Modifier 是平级开关,不是嵌套层级。写成 btn--large-loading 看似省事,实则掩盖了状态组合逻辑,JS 控制时极易漏掉某一个类。
- 必须分开写:
btn--large btn--loading,这样 JS 切换状态才可控(el.classList.toggle('btn--loading')) - 不能作用于 Element 的 Modifier:
btn__text--large❌,字体大小是按钮整体的视觉变体,应由btn--large统一控制 - 禁止伪修饰符:
btn--btn-lg或btn--size-lg都不对;统一用业务语言:btn--primary、btn--compact、btn--outline - CSS-in-JS 场景下,别在 Styled Component 里写
&__icon,那会破坏 BEM 的可预测性;用clsx拼字符串更可靠
和 Tailwind 或 CSS-in-JS 共存时 BEM 还要不要写 class 名
要,但角色变了:BEM 不再是手写 class 字符串的模板,而是组织样式逻辑的思维框架。
- Tailwind 项目里,别手动写
class="card__header"再配@apply,这既没发挥 utility 优势,又丢了结构语义;应该用@layer components定义@apply flex p-4 bg-white rounded-lg,并明确注释这是card__header的视觉实现 - CSS-in-JS(如 Emotion)中,BEM 主要体现在
cx或 className 生成逻辑里,比如`${block}__${element}`,而不是硬编码字符串 - 所有构建工具(Webpack / Vite)对 BEM 的校验都依赖类名格式,如果用了 CSS Modules 却没按
Card.module.css命名,postcss-bem可能直接跳过解析 - 最常被忽略的一点:BEM 类名一旦写进 HTML,就承担了 JS 选择器职责;
document.querySelector('.btn--loading')是合法且推荐的,别为了“语义化”又加一堆 data-* 属性
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










