BEM命名规范通过单类名选择器(如.block__element--modifier)实现一次哈希查找,避免嵌套选择器(如.block .element)从右向左逐层回溯父节点带来的性能损耗,DOM越深、节点越多,差距越显著。

因为浏览器解析 CSS 时,.block__element--modifier 这种单类名选择器能直接哈希查找,而嵌套选择器如 .block .element 必须从右往左逐层回溯父节点——DOM 越深、元素越多,性能差距越明显。
浏览器匹配 CSS 的真实路径是“从右往左”
关键选择器(最右边那个)决定初始查找范围。写 .header__logo--dark,浏览器直接查 class 表;写 .page-home .header .header__logo--dark,它得先找所有 .header__logo--dark 元素,再挨个往上确认父级是否匹配 .header,再确认 .page-home。移动端 DOM 深、节点多时,这个过程开销显著上升。
- DevTools → Elements → 选中元素 → Computed → Styles 面板里,一眼就能看出有没有空格——有空格就是潜在性能隐患
- Sass 中写
.header { &__logo { } }安全;但写.header { & .header__logo { } }就会编译出带空格的选择器 - 构建后用
grep -r "\.[a-z]\+ \.[a-z]" dist/快速揪出残留的空格选择器
BEM 不减少重排重绘,但能间接避开重排陷阱
BEM 本身不改变 layout 计算逻辑,也不让 width 或 display 变快。但它通过强制扁平结构,天然规避了因嵌套选择器引发的“意外重排链”:
- 禁止
.list .item,就避免了改.list的display时整列触发重排 - 常见卡顿误判:团队以为“用了 BEM 就能优化列表滚动”,结果仍卡——问题其实出在未限制
height、用了flex-wrap + 百分比 padding,或在:hover里改了margin -
.card:hover .card__title看似合理,但运行时需验证父级 hover 状态;应改为.card--hovered .card__title,由 JS 切换修饰符
Specificity 和体积控制是速度的隐性支柱
单类名选择器权重固定为 10,没有叠加风险。而 .header .logo 权重已是 20,后续想覆盖就得提权、加 !important,甚至引入更深层嵌套,形成恶性循环:
- 常见错误:
.header__nav-item:hover不生效,结果发现 CSS 写了.header__nav .header__nav-item——既违反 BEM 语义,又凭空加了 10 点权重 - 所有 BEM 规则必须以单个类名为选择器起点:
.search-form__submit✔️,.search-form .search-form__submit❌ - 多个 Modifier 共存时,避免重复定义同一属性(比如
.button--primary和.button--large都设background),否则后声明者必赢,覆盖逻辑失控
真正容易被忽略的是:BEM 的性能收益完全依赖最终生成的选择器字符串是否干净。哪怕 Sass 文件写得再规范,只要构建产物里混入一个 .card .content p,整条链路的匹配效率就退回到嵌套模式。检查不能只看源码,必须盯住 DevTools 的 Styles 面板和构建后的 CSS 文件。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











