BEM修饰符应表达语义而非视觉,尺寸用compact/dense/standard表布局意图,颜色用danger/success表业务状态,状态用loading/error表可感知UI反馈,多修饰符需独立声明并用CSS变量控制优先级。

尺寸Modifier不是“小中大”,而是紧凑态、密集态、标准态
尺寸类修饰符容易被当成视觉值映射,比如写 button--small 或 card--large。这违反 BEM 的语义隔离原则——“小”是响应式行为的结果,不是组件固有状态。真正该表达的是密度或布局意图:button--compact 表示按钮在有限空间内压缩排版,card--dense 表示信息密度提升(如表格行高减小),card--standard 是默认无修饰的基线形态。
常见错误:
-
user-card--small:尺寸随断点变化,应由@media控制,或用user-card--compact配合容器上下文判断 -
icon--24px:含单位,破坏主题切换能力;应为icon--size-sm,其实际像素值由 CSS 变量--icon-size-sm定义 - 把尺寸当布尔开关:
input--full-width是合理状态(输入框是否占满父容器),但input--wide模糊,无法判断是相对宽还是绝对宽
颜色Modifier必须对应业务语义,不能是视觉值
写 button--red 或 badge--green 是典型反模式。颜色本身不是状态,而是状态的视觉表现。BEM 修饰符要回答“它是什么”,而不是“它看起来像什么”。button--danger 表示该按钮触发高风险操作(如删除),badge--success 表示任务已完成,这些命名可被 JS 安全读取、被屏幕阅读器识别、被暗色模式变量统一覆盖。
关键判断点:
立即学习“前端免费学习笔记(深入)”;
- 能否用 ARIA 属性描述?
aria-live="polite"对应status-badge--live,而不是status-badge--blue - 换主题时是否需要改 HTML?如果换成暗色模式后得把所有
--red改成--error,说明命名已泄漏视觉实现 - 是否与设计系统 Token 对齐?
button--primary应映射到--color-button-primary,而非硬编码#007bff
状态Modifier只表达 UI 层可感知的、有明确反馈的行为信号
状态修饰符不是后端响应码的镜像,也不是 DOM 属性的搬运工。它必须让开发者一眼看出交互后果:button--loading 意味着禁用点击 + 显示 spinner + 文字灰度降低;form-field--error 意味着边框变红 + 显示提示文案 + 输入框获得焦点时自动滚动到视口。
容易踩的坑:
-
button--pending:pending 是网络层概念,UI 层无法直接呈现;应拆解为button--loading(请求中)或button--submitting(表单正提交) -
modal--open:这不是组件自身状态,而是容器控制的结果;应由is-modal-open这类运行时类处理,BEM 修饰符只用于modal--expanded(内容展开态)这类固有变体 - 伪类混入修饰符:
button--hover不存在,:hover 是 CSS 原生机制,修饰符只用于可编程控制的状态
Modifier叠加时不能嵌套,但需显式声明样式优先级
BEM 允许多修饰符共存,如 button button--primary button--loading,但禁止 button--primary-loading 或 button--primary--loading。每个修饰符独立生效,CSS 中必须显式写出组合效果:
.button--primary.button--loading {
opacity: 0.7;
cursor: wait;
}
否则,.button--loading 的禁用样式可能被 .button--primary 的背景色覆盖。更稳妥的做法是用 CSS 自定义属性透传状态:
.button {
background-color: var(--button-bg, #fff);
}
.button--primary {
--button-bg: var(--color-button-primary, #007bff);
}
.button--loading {
--button-bg: var(--color-button-loading, #ccc);
}
这样即使叠加,变量会自然覆盖,无需手写组合选择器。
最常被忽略的复杂点:Modifier 和 Element 的层级关系。比如 card__header--sticky 是合法的,但 card--sticky__header 不合法——修饰符只能挂在 Block 或 Element 上,不能跨级修饰。而一旦出现 card__header--sticky,就要确认 sticky 是否真是 header 的固有变体,还是整个 card 的布局行为;后者应写作 card--sticky 并通过子元素继承控制 header 行为。


















