& 不可跨层引用父选择器,仅拼接直接外层选择器;bem 类名需用 @at-root + #{&} 安全生成;媒体查询中 & 仍指外部父选择器,不可单独使用。

为什么 & 不能跨层引用父选择器
& 在 Sass 中不是 DOM 查询器,它只做编译期字符串拼接,且严格绑定**直接外层选择器**。写 .card { .header { &.active { } } } 生成的是 .card .header.active,而非 .card.active .header——& 永远不会跳过中间层级去“找”更外层的 .card。
常见错误是以为嵌套越深 & 就能“爬得越高”,结果编译出的选择器语义错乱、浏览器无法匹配。比如:.block { &__elem { &__subelem { } } } 直接报错:Sass 不允许 & 后紧跟另一个 &__。
真正需要影响上层容器时,必须跳出嵌套流:@at-root 是唯一可靠路径。
如何安全生成 BEM 元素与修饰符类名
BEM 要求类名扁平(如 .menu__item--hovered),但直接在嵌套中用 &__item { &--hovered { } } 会产出带空格的后代选择器(.menu__item --hovered 非法),或错误拼接为 .menu__item.menu__item--hovered(两个类并列,破坏 BEM 语义)。
正确做法是用 @at-root + 插值:.menu { &__item { @at-root #{&}--hovered { color: red; } } } → 输出 .menu__item--hovered。
注意以下要点:
-
#{&}必须加引号包裹,否则 Sass 3.4 之前版本会报错 - 修饰符(
--xxx)必须和元素同级,禁止在&__item块内再嵌&--modifier - 不要混用:
&.highlighted表示“同时拥有两个类”,&--highlighted才是新类名 - 伪类复合时(如
.btn:not(.disabled))慎用 &,&__icon会生成非法选择器
媒体查询和伪类中 & 的行为限制
& 在 @media 或 :hover 内部依然有效,但它引用的仍是**外部最近的父选择器**,不是媒体查询本身。例如:.component { @media (min-width: 768px) { &__header { font-size: 1.2em; } } } → 输出 @media (min-width: 768px) { .component__header { } }。
关键限制:
- 不能在
@media块里单独写&,否则报错Invalid CSS after "&": expected selector -
&:before和&::before效果不同:后者才符合现代规范,前者可能被部分浏览器忽略 -
@supports中使用 & 存在解析不稳定风险(旧版 Dart Sass 可能漏前缀或崩溃),建议升级到最新稳定版
嵌套过深时最易被忽略的验证点
所有 @at-root + #{&} 的写法,本质都是字符串重组,和实际 DOM 结构完全无关。你写的 .card { @at-root #{&}__body { } 看似“提升了一层”,但输出就是 .card__body,它不感知该元素是否真在 .card 内部——这恰恰是 BEM 的设计前提,也是最大陷阱:编译结果必须人工验证,不能靠“看起来像”就认为逻辑成立。
尤其当项目混合使用原生 CSS 嵌套(.card { .body { })和 Sass 的 & 时,两套机制对“嵌套”的理解完全不同,容易误以为功能等价。记住:原生嵌套生成的是后代选择器,Sass 的 & 生成的是拼接类名——目标不同,不可混用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











