Modifier 堆叠失控是 HTML 体积暴涨的主因,如 user-card__avatar--size-lg--theme-dark--is-loading 类名冗余导致首屏变慢;Modifier 应离散互斥、总数≤5,禁用形容词堆叠与样式细节表达,CSS 自定义属性替代冗余类名,组件边界不清比类名长更致命,工具链缺失使 BEM 难以落地。

Modifier 堆叠失控是 HTML 体积暴涨的主因
真正拖慢首屏的不是 BEM 本身,而是像 user-card__avatar--size-lg--theme-dark--is-loading 这种 Modifier 连续叠加。它在列表渲染 20 次时,光这个类名就多出近 1.2KB(未 gzip),SSR 场景下直接抬高 TTFB 和 HTML 解析耗时。
常见错误现象:card__title--large--bold--highlighted —— 这不是 BEM,是命名失控。Modifier 应该是离散、互斥、可枚举的状态,不是形容词堆叠。
- 一个 Block 的 Modifier 总数建议 ≤ 5 个(如
--primary、--disabled、--sm、--lg、--outline) - 禁止用 Modifier 表达样式细节(如
--bg-blue-500),这类应由 CSS 自定义属性接管 - 避免手动拼接:
className={`${block}__${elem} ${block}--${mod}`}容易漏空格、错顺序,且无法被PurgeCSS安全识别
CSS 自定义属性替代冗余 Modifier 类名
当 Modifier 实际只控制颜色、间距、圆角等可变量时,硬写类名等于把配置逻辑重复塞进 HTML。CSS 自定义属性能把这部分抽离到样式层,HTML 回归语义本质。
例如,把 button--theme-primary--size-xl--variant-outline 缩减为 button,然后在 CSS 中定义:
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
:root {
--btn-theme: #007bff;
--btn-padding: 12px 24px;
--btn-border-radius: 8px;
}
- 状态类名只保留布尔型:
button--disabled✅,button--on-dashboard-page❌ - 多个子元素共用同一状态时,提升到父 Block:
dashboard--is-loading,再用选择器批量控制.dashboard--is-loading .dashboard__header - 变量只定义在 Block 层级,Element 和 Modifier 通过组合使用,而不是各自声明
--button-hover-bg-color这类泛滥变量
组件边界不清比类名长更致命
BEM 类名过长本质是组件边界没划清——缩写类名治标不治本,强行截断反而让 user-card__avatar--size-lg 变成 uc-avt--l,调试时根本看不出它在干啥。
判断标准就一条:这个子结构有没有自己的状态、行为或复用场景。有,就升为 Block;没有,才考虑精简命名。
-
status-badge出现在用户列表、订单卡片、通知弹窗里 → 必须独立 Block,不该叫user-card__status -
price-tag有自己的颜色逻辑、动画、点击反馈 → 不该依附于product-card命名 - 一旦出现三层下划线(如
.header__nav__item__link),说明已经违背 BEM 初衷:Block 应是独立可复用单元,__只用于描述该 Block 内的直接子元素
工具链没跟上,BEM 就只是纸面规范
手动拼写 card__content--hover 确实反人类,但真正卡点不在命名规则,而在缺乏工具链支撑。BEM 的价值只有在配合编辑器提示、构建时校验才真正落地。
- VS Code 装
PostCSS Language Support插件,能高亮识别__/--语法并提示拼写 - 用
stylelint配stylelint-selector-bem-pattern规则,禁止出现.btn-primary这类非 BEM 写法 - PostCSS 插件如
postcss-bem-linter能实时报错,而postcss-bem可自动把.button { &__icon { } &--primary {} }编译成完整前缀 CSS - 插件不会检查 HTML 里是否真写了
button__icon,只校验 CSS 写法,所以需配合自动化测试抓漏用类
最常被忽略的一点:页面容器和功能 Block 混为一谈。比如把整个 dashboard-page 当成一个 Block,然后往里塞 dashboard-page__user-card__header__title —— 其实 user-card 和 dashboard-page 是组合关系,不是隶属关系。拆开之后,HTML 更轻,CSS 更易维护,连 JS 绑定事件都更干净。


















