浏览器匹配CSS选择器是从右向左进行的,即先定位关键选择器(最右侧部分)如.title,再逐级向上验证父级结构,每增加一层嵌套就多一次DOM回溯,4层即达性能临界点,BEM单类名可彻底规避回溯。

浏览器匹配选择器是从右往左查的,不是从左到右走DOM
写 .page .main .content .card .title 这种5层选择器时,浏览器不会先找 .page 再往下钻,而是:先找出所有 .title 元素,再对每个 .title 向上检查是否在 .card 里、该 .card 是否在 .content 里……每多一层,就多一次 DOM 树向上遍历。DOM 节点一过500个,Recalculate Style 很容易超20ms,滚动直接掉帧。
4层就是硬性性能临界点,不是建议,是实测卡顿起点
低端 Android WebView 实测数据表明:.a .b .c .d(4层)已触发明显滚动卡顿;5层以上,在虚拟滚动列表这类 layout 触发频繁的区域,CPU 占用常飙至 90%+。这不是编译慢,是运行时真卡——你改一个 classList.add("is-active"),样式可能根本没生效,因为选择器太长、权重太高、压根没被匹配上。
@at-root 不是“逃逸键”,它只解决本该平级却误嵌套的问题
@at-root 不能用来给4层缩进打补丁,它只适合切断逻辑上不该继承父前缀的规则:
- 错误写法:
.modal { .header { @extend %text-center; } }→ 编译出.modal .header .u-text-center,完全冗余 - 正确写法:
.modal { @at-root .u-text-center { text-align: center; } }→ 输出.u-text-center,单类名,零回溯 - 可控提级:
@at-root (with: .theme-dark) { .button { color: white; } }→ 输出.theme-dark .button,只加必要上下文 - 特别注意:
@media块内禁用&嵌套,否则外层有.layout .dashboard时,@media (min-width: 768px) { .card { &__body { } } }会产出6层选择器
BEM 不是命名规范,是匹配路径切断协议
BEM 的核心作用,是让每个样式只依赖一个类名,彻底绕过浏览器向上查找父级的过程:
立即学习“前端免费学习笔记(深入)”;
-
card__title必须显式出现在 HTML 中:<h2 class="card__title">✅ 匹配单类,零回溯 - 禁止
card__header__logo这种跨层 Element,应拆为card__header和card__logo - 修饰符必须能独立存在:
button--loading不能依赖button类才生效,否则element.classList.add("button--loading")会失效 - SCSS 嵌套中若出现
&__body,必须确保 HTML 真有card__body这个类,缺了就完全不匹配
.item .title),每次 layout 触发都要重跑整条匹配链。BEM 类名能规避,但前提是 HTML 中真实应用,而不是靠结构推导。



















