&不是父元素而是完整选择器字符串,故&:hover会展开整条父路径导致权重飙升,如.modal .content .form:hover(0,3,1);BEM中&__element会因空格生成后代选择器,须用@at-root #{&}__element确保扁平类名。

& 不是“父元素”,而是“当前嵌套层级的完整选择器字符串”——理解这点,90% 的错误就消除了。
为什么 &:hover 会生成超高权重的选择器?
因为 & 展开的是整个父路径,不是你肉眼看到的“最近那个类”。比如在 .modal .content .form { &:hover { } } 中,& 是 .modal .content .form,所以编译出 .modal .content .form:hover(权重 0,3,1),而不是你想要的 .form:hover(0,1,1)。
- 常见错误现象:悬停样式覆盖不了
.form--highlight,控制台里发现权重差两级,只能加!important硬顶 - 真正根源:伪类必须紧贴语义类,不能靠
&拖着整条 DOM 路径走 - 安全写法:把状态逻辑提到顶层,单独写
.form:hover { },或抽成工具类.u-hover-bg-blue { &:hover { background: blue; } } - 绝对禁止:
#header { &:focus { } }→ 编译为#header:focus(权重 100+),后续基本无法覆盖
&__element 为什么编译出带空格的后代选择器?
SCSS 的 & 默认拼接行为就是“字符串 + 空格 + 后缀”,所以 .card { &__title { } } 输出的是 .card .card__title,而非 BEM 要求的单类名 .card__title。这会导致样式强依赖 HTML 结构,一改 DOM 就失效。
- 根本原因:
&是选择器字符串,不是命名前缀;BEM 的__是扁平类名,不是嵌套关系 - 唯一可靠方案:
@at-root #{&}__title { }→ 输出.card__title - 错误示范:
.button { &:disabled { &__icon { } } }违反 BEM 原则,.button__icon应独立存在,状态应通过.button__icon:hover或修饰符.button__icon--disabled控制 - 漏写基础类(如只用
.card__title--large不写.card__title)会让样式静默失效,devtools 里查不到规则匹配
嵌套超过 3 层时 & 开始失控
4 层嵌套是性能和可维护性的硬拐点。浏览器从右往左匹配 .page .section .content .card .title,DOM 节点多时明显卡顿,Lighthouse 直接报 “Avoid overly specific selectors”。
立即学习“前端免费学习笔记(深入)”;
- 每多一层,特异性 +10:
.a .b .c .d比.d难覆盖 100 倍 -
&前有无空格决定语义:.card { .header { &__title { } } }中&是.card .header,结果是.card .header__title(错乱) - 想保留上下文又不爆权重?用变量暂存:
$block: ".card"; #{$block}__title { color: red; } - 用
@at-root和>主动切链:.card { > .header { > h1 { } } }→ 编译为.card > .header > h1,更短、更可控
@at-root 用错位置,& 就彻底失效
@at-root 不是万能覆盖工具,它只负责提级选择器生成位置。写在嵌套块内部、加了前导选择器、或混在 @media 里,都会让它失效。
- 错误写法:
.modal { .is-loading { @at-root .is-loading { } } }→ 编译后仍是.modal .is-loading - 正确写法:
.modal { @at-root .is-loading { opacity: 0.5; } } - 要脱离媒体查询?必须写
@at-root (without: all) .theme-dark { },默认@at-root只跳出选择器嵌套 -
&在@at-root内部无效:.card { @at-root &__header { } }直接报错,因为&依赖嵌套上下文,而@at-root已清除它 - 别用
@at-root替代 Vue 的:deep()——前者生成全局类,后者是构建时作用域穿透,目的和机制完全不同
最常被忽略的其实是:SCSS 嵌套不是组织代码的手段,而是暴露设计缺陷的探针。当 & 开始让你反复调试权重、删空格、补 @at-root,说明语义边界已经模糊,该重构类名或拆组件了。


















