BEM 必须严格遵循 block__element--modifier 命名规范,禁用裸类名、无语义命名、后代选择器及动态拼接类名,确保样式归属明确、可维护、可调试。

直接写 .btn 或 .header 就算用了 BEM,也等于没用——它立刻让样式失去归属、引发跨组件污染,协作两周内就会失控。
裸类名没有 block 归属,等于扔进全局池子
这类名字不带 __ 或 --,既不是元素也不是修饰符,无法回答“它属于哪个功能单元”。多人并行时,.btn 可能在登录页定义 padding,在弹窗里又被重写 margin,谁生效取决于加载顺序,而不是业务逻辑。
-
.btn、.header、.card全部违规;必须写成.login-form__submit、.header__logo、.product-card__image - 目录结构要和 block 名对齐:
/components/user-card/UserCard.css里只允许出现.user-card开头的类 - 禁用
.container、.wrapper、.section-2这类无业务语义的命名,它们天然重复、无法保证唯一性
__ 和 -- 混用或漏写,工具链直接失效
IDE 跳转、Sass 嵌套、stylelint 校验全依赖 __ 作为块-元素分隔符。少打一个下划线,比如写成 user_card 或 btn-primary,所有自动化能力就断了。
-
user-card__avatar✅,user_card__avatar❌(单下划线) -
button--disabled✅,button-disabled❌(单短横) -
card__title--large❌——修饰符挂错位置,尺寸变化通常影响整个卡片,应写card--large,而非仅标题变大 - 禁止嵌套修饰符:
button--primary--disabled合法,但button--primary--disabled--loading会超出可维护边界
SCSS 里写后代选择器,BEM 封装性当场归零
BEM 要求最终 CSS 是扁平类名,不依赖 DOM 层级。一旦写 .card { .title { } },编译出 .card .title,HTML 加个 div wrapper 或改个标签,样式就断,且无法反向定位来源。
立即学习“前端免费学习笔记(深入)”;
- 正确写法只用
&__title和&--loading,禁止&__content { &__icon { } }(会生成非法的.card__content .card__content__icon) - 遇到“元素里的图标”,别硬塞:把
.table-cell__status-icon改为独立块.status-icon+.status-icon--in-table - 空格是危险信号:
&__item &__icon中间有空格 → 后代选择器;&__item__icon无空格 → 非法三层嵌套
JS 中手拼类名,重构时悄无声息地崩
写 className={`card__title ${isActive ? 'card__title--active' : ''}`} 看似简单,但每加一个状态就得补一串三元,极易漏掉空格、拼错大小写,DevTools 里也看不到完整语义。
- 禁止动态构造
__或--部分:`${block}__${elem}`若elem来自 props,值含空格就直接失效 - 用
clsx声明式组合:className={clsx('card__title', { 'card__title--active': isActive })} - React 中建议定义常量:
const BLOCK = 'user-profile',后续所有类名基于它生成,避免拼写不一致 - 所有 BEM 全称必须硬编码,不能靠变量拼接——否则 DevTools 里看不到完整类名,调试成本陡增
真正卡住团队的不是规则多难,而是每次写 class 前没确认:这个样式属于哪个独立功能单元?它会不会在别的上下文里意外生效?工具链可以拦住语法错误,但归属意识得靠人盯住。


















