BEM本身不减少重排,它只是命名约定;真正影响重排的是样式计算粒度和DOM结构稳定性,BEM仅通过扁平结构、明确作用域和约束Modifier间接规避重排陷阱。

直接说结论:BEM 本身不减少重排(reflow),它也不参与 DOM 渲染过程;所谓“BEM 提升列表渲染性能”是常见误解。真正影响重排的是 CSS 选择器匹配开销、样式计算粒度和 DOM 结构稳定性,BEM 只在后两者上间接起作用。
为什么 BEM 类名不会让浏览器重排变快
BEM 是命名约定,不是运行时机制。浏览器做重排时只关心:哪些元素的几何属性变了(宽高、位置、display 等)、哪些样式规则被触发、这些规则是否需要重新计算布局。类名写成 list__item--active 还是 item-active,对 layout 引擎毫无区别——只要最终生成的 CSS 规则里没用到 position: absolute、float、宽高依赖父容器等易触发重排的声明,重排次数就不会因此减少。
常见错误现象:团队以为“用了 BEM 就不用优化列表”,结果滚动长列表时卡顿依旧,甚至因类名过长+重复应用导致 JS 拼接 className 变慢,反而拖累首屏。
- BEM 不改变 CSSOM 构建速度,也不跳过 layout 阶段
- 浏览器不解析类名语义,只按字符串匹配规则;
.list__item和.item的匹配成本几乎一致 - 真正拖慢渲染的是:未限制列表项高度、用了
flex-wrap+ 百分比内边距、或在:hover里改了width/margin
但 BEM 能帮你在列表中避开重排陷阱
它通过强制扁平结构和明确作用域,让开发者更容易写出「不意外触发重排」的 CSS。比如:list__item 不能依赖 .list > .item 这种父子关系,就天然规避了因父容器 display 切换(如 block ↔ grid)引发的整列重排。
- 禁止嵌套选择器 → 避免改一个
.list的overflow,连带让所有.list .item重算定位 - Element 必须属于且仅属于一个 Block → 防止列表项被多个上下文样式交叉影响(如
.card .list__item和.sidebar .list__item冲突后加!important,最终 layout 权重失控) - Modifier 只表达状态(
--loading、--expanded),不用于布局(禁用--left、--full-width)→ 减少因状态切换导致几何属性变更
列表场景下 BEM 的实操红线
在 VirtualList 或 react-window 这类高性能列表中,BEM 类名必须满足三项硬约束,否则会放大渲染负担:
- 所有列表项根元素必须只挂一个 Block 类,例如
<li class="user-list__item">,禁止额外加class="user-list__item list__item"这类冗余叠加 - 不要在 Modifier 中写影响 layout 的声明:
.user-list__item--collapsed { height: 0; overflow: hidden; }是 OK 的,但.user-list__item--collapsed { display: none; }会导致虚拟滚动计算错 offsetHeight,必须避免 - 动态类名拼接必须用
clsx或类似工具,禁止手拼:className={`user-list__item ${isActive ? 'user-list__item--active' : ''}`容易漏空格或大小写错,Linux 构建失败;应统一用clsx('user-list__item', { 'user-list__item--active': isActive }) - 若列表项含图片或异步内容,用
user-list__item--loading占位,但该 Modifier 对应的 CSS 必须预设固定宽高(如min-height: 48px),否则内容加载后会触发重排
真正降低列表重排的配套动作
BEM 是骨架,但得配上具体手段才能见效。列表性能卡点往往不在类名,而在以下几处:
- CSS 中对列表项使用
contain: layout style paint(现代浏览器支持),能明确告诉引擎:“这个元素的 layout 变化不会影响外面”,大幅减少重排范围 - 避免在
scroll事件里直接改className;改状态用requestIdleCallback或节流后的setState,确保不打断帧渲染 - 第三方 UI 组件(如 Ant Design 的
Table)内部类名不遵循 BEM?没问题,但务必在外层包一层my-order-list__ant-table-wrapper,用contain隔离其样式泄漏和 layout 影响 - 构建时用
postcss-bem-linter校验:报错Unexpected selector ".user-list .user-list__item"就说明有人偷偷写了后代选择器,必须干掉——这种写法会让浏览器每次匹配都向上遍历 DOM 树
最常被忽略的一点:BEM 的价值不在“写得漂亮”,而在于让团队在代码评审时一眼揪出 .list-item 这种裸名——它没有 Block 前缀,意味着可能被全局污染,一旦加了 hover 动画,整个列表滚动就可能抖动。守住这条线,比纠结类名长度重要得多。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











