BEM规范要求块(Block)必须是语义完整、职责单一、DOM自包含的独立单元,如.button、.card;元素(Element)用双下划线连接,如.button__icon;修饰符(Modifier)用双中划线连接且须与块/元素共存,如.button--disabled,避免将CSS属性直译为类名,确保类名自带上下文、可被工具静态识别、HTML与CSS严格对齐。

直接用 .btn 或 .card 当公共类,反而会让 CSS 越改越臃肿——因为没区分结构归属和视觉变体,后续只能靠 !important、后代选择器或一堆修饰类硬扛。
为什么 .btn 不能当通用公共块
它不是语义完整、职责单一、DOM 自包含的单元。一个 .btn 出现在 .header、.modal、.sidebar 里时,实际需要的边距、字体大小、禁用态逻辑完全不同。结果就是:
- 写
.header .btn覆盖样式,但破坏了作用域隔离 - 加
.btn--header这类伪修饰符,导致类名爆炸且语义混乱 - 删一个类不敢动,因为没人知道它到底在哪被用了
真正可复用的块必须是 .button、.card、.form-field 这种:有自己完整的 HTML 结构(比如带图标、加载态封装),不依赖父容器存在。
postcss-bem-linter 怎么用才不白装
它只校验 CSS 写法,不检查 HTML 是否真写了对应类名。漏写 .button__icon 却在 CSS 里定义了它,样式就失效,还查不到原因。
立即学习“前端免费学习笔记(深入)”;
- 先配好
allowedElements,比如['__icon', '__text', '__loading'],防止误写.button__img - 开启
strict模式,让.button--Primary(大写 P)直接报错 - 配合 DevTools 的 Styles 面板,筛选被划掉的属性,右键 → “Break on attribute modification”,点几次 UI 操作,看哪些旧样式被动态覆盖
修饰符(Modifier)怎么写才不增加体积
--primary、--disabled 是合理的;--blue、--lg、--mt-4 是危险信号。后者本质是把 CSS 属性映射成类名,最终生成一堆碎片规则。
- 修饰符必须和块/元素共存:
.button--disabled✅,单独用.button--disabled❌ - 尺寸、颜色等视觉值交给 CSS 变量控制:
--color-primary统一管理,.button--primary只负责组合 - 避免
.button--size-small+.button--size-medium这种并列声明——改主题时要改十几处
clsx 在 React 里怎么配合 BEM 不翻车
手动拼 className={`${block}__${el} ${block}--${mod}`} 容易漏空格、错分隔符,导致渲染出无效类名,最后只能靠多写 CSS 规则兜底。
- 每个组件顶部定义
const BLOCK = 'user-avatar',所有类名都基于它生成,不拼接动态块名 - 用
clsx(BLOCK, `${BLOCK}__icon`, { [`${BLOCK}--loading`]: isLoading }),保证输出稳定 - 别在
useMemo里反复调用clsx却没缓存结果,或传整个对象进去导致浅比较失效
BEM 的关键不在下划线数量,而在是否让每个类名自带上下文、能否被构建工具静态识别、以及 HTML 和 CSS 是否真正对齐——这三处松动,冗余就会悄悄长回来。


















