React中BEM规范核心是Block名必须与文件名完全一致,否则styles对象中类名将静默undefined;需严格大小写匹配、禁用字面量拼接、Modifier须表稳定状态且依附Block/Element。

React组件里用BEM,核心就一条:Block名必须和文件名完全一致,否则styles对象里根本找不到对应类名——不是报错,是静默undefined,调试时最头疼。
为什么styles.card__footer总是undefined?
这不是CSS写错了,大概率是文件名和Block名没对齐。比如组件叫Card,CSS文件必须是Card.module.css,里面所有类必须以.card开头;写成.Card、.ui-card或.product-card,styles['card__footer']就永远是undefined。
- 验证方法:打开编译后生成的CSS文件,看类名前缀是不是
Card_开头 - 大小写敏感:文件是
card.module.css,JS里却按Card访问,styles.card__footer会是undefined,但styles['card__footer']可能取得到——这是典型大小写不匹配 - 开发期建议配置
localIdentName=[name]__[local]___[hash:base64:5],调试时一眼能看出Card__footer___abc12这种来源
className里手拼字符串为什么总出问题?
写{`card ${isActive ? 'card--active' : ''} ${hasIcon ? 'card__icon' : ''}`}看似省事,实际埋了三个坑:漏空格、连字符写成单横线(card-active)、isActive为null时留下多余空格。更关键的是,它绕过了CSS Modules的哈希校验,拼错类名样式就静默失效。
- 正确做法是封装一个绑定Block的生成器:
const cardBem = bem('card'),再用classnames统一处理 - 所有传给
classnames的值必须来自cardBem,禁止混入字面量字符串(如'card--disabled') -
cardBem.e('footer')返回'card__footer',再通过styles[...]查真实哈希名,而不是硬编码styles.card__footer
Modifier为什么不能写card--mobile或card--v2?
Modifier必须表达稳定、可枚举的状态,比如card--loading、card--expanded,而不是位置(--mobile)、版本(--v2)或视觉描述(--blue)。前者会随业务变化而失效,后者破坏语义一致性。
立即学习“前端免费学习笔记(深入)”;
-
card--mobile意味着未来加个card--tablet,再加个card--desktop——这不是状态,是断点逻辑,该收口到媒体查询里 -
card--v2这种临时标签无法被类型系统约束,上线后没人敢删,变成技术债 - Modifier必须依附于Block或Element存在,不能单独使用:
card--loading合法,card__header--loading越界(header自身没有加载态,是card整体在加载)
BEM真正难的不是语法,而是让所有人守住Block边界:一个CSS文件里只准有一个Block名,不允许混写.card和.button;每个组件顶部声明const BLOCK = 'card',所有派生类名都基于它生成——改名时只需动一行,而不是全局搜替换。


















