BEM合法命名要求结构清晰、边界明确:card__title--large合法因修饰符作用于element,而card__title__icon非法因违反element不可再嵌套的规则;button--primary语义明确可维护,button--red仅描述颜色易导致维护困境。

BEM不是加下划线的格式技巧,而是用命名强制约束组件边界——类名写错,往往意味着DOM结构或职责划分本身就有问题。
为什么card__title--large合法,而card__title__icon非法
BEM只承认一层嵌套关系:block → element,不承认 element → sub-element。所谓“标题里的图标”,在BEM视角里只有两种合理解法:
- 如果
icon是card__title的视觉附属(比如标题左侧小图标),应作为修饰符:card__title card__title--with-icon - 如果
icon具备独立语义或复用可能(如状态徽标),它就该升格为新 block:badge,再通过上下文组合使用:card__title <badge badge--status="online"></badge> - 强行写
card__title__icon会破坏隔离性——改card__title的 padding,可能意外影响card__title__icon的定位逻辑
button--primary和button--red的区别在哪
修饰符必须表达可预测、可维护的状态语义,而非视觉快照:
-
button--red是危险信号:换品牌色就得全局搜索替换,且无法推断其业务含义(是“删除”?“警告”?还是“默认CTA”?) -
button--primary明确表达意图,CSS里可映射到$color-primary变量,主题切换时只需改变量值 - 多个修饰符要并列使用,不链式叠加:
button button--primary button--disabled✅,button--primary--disabled❌
SCSS里怎么安全写BEM,避免生成后代选择器
SCSS嵌套本身不违反BEM,但一不留神就会写出破坏作用域的选择器:
立即学习“前端免费学习笔记(深入)”;
- 正确写法(单层嵌套,用
&__和&--):.card { &__title { font-size: 1.2rem; } &--horizontal { display: flex; } } - 错误写法(带空格 = 后代选择器):
.card { &__title { .icon { ... } // 生成 .card__title .icon,耦合了内部结构 } } - 真需要关联子元素样式,优先用属性选择器:
[data-role="card-title-icon"],比.card__title__icon更可控
React组件中classnames怎么配BEM才不翻车
直接拼字符串如className={`card__header ${isExpanded ? 'card__header--expanded' : ''}`看似可行,但隐患明显:
- Block名散落在各处,某天把
card改成ui-card,得手动搜全项目所有card__*; - Modifier状态逻辑分散,加个
isLoading又要补三元,易漏; - 推荐做法:在组件顶部定义
BLOCK = 'card',再用classnames统一派生:import cn from 'classnames'; const BLOCK = 'card'; // ... <div className={cn(`${BLOCK}`, `${BLOCK}--horizontal`)}> <h3 className={cn(`${BLOCK}__title`, { [`${BLOCK}__title--compact`]: isCompact })} /></div>
最易被忽略的一点:BEM的约束力不在CSS里,而在开发者对“这个东西到底算不算独立Block”的持续判断——命名没写错,不等于结构设计合理;写对了__和--,不等于避开了职责混乱。每次新增类名前,先问一句:它能不能脱离当前父级单独存在?有没有可能被其他页面复用?答案是否定的,那大概率不该是一个Block。


















