&代表当前嵌套上下文的完整选择器链,保留原有顺序结构;在BEM等场景易误用导致空格分隔错误;@media/@supports内&引用外部父选择器;插值#{}更可控但需字符串变量且不支持@extend跨边界。

父选择器 & 在嵌套规则中的基础行为
很多人以为 & 就是“把外层选择器原样拼上去”,其实它代表的是**当前嵌套上下文的完整选择器链**,且会保留原有顺序和结构。比如在 .btn 里写 &:hover,生成的是 .btn:hover;但若在 .btn.primary 里写 &.disabled,结果是 .btn.primary.disabled,不是 .btn.disabled。
- 嵌套层级越深,
&展开的前缀越长,容易意外放大选择器特异性(specificity) - 不能在
@at-root外部直接用&—— 它只在嵌套块内有效,否则报错Invalid CSS after "&": expected selector, was ";" - 如果父选择器含伪类或属性选择器(如
.card:nth-child(2)),&:before会变成.card:nth-child(2):before,注意浏览器对复合伪类的支持差异
用 & 拼接 BEM 类名时的常见翻车点
BEM 是 & 最常被误用的场景。比如想写 .block__element--modifier,有人会这样写:
.block {
&__element {
&--modifier { color: red; }
}
}
结果生成的是 .block .block__element .block__element--modifier —— 多了两层空格,完全不是想要的连字符类名。
- 正确做法是把修饰符写在元素同一级:
&__element--modifier,而不是嵌套在&__element里面 - 更安全的写法是显式拼接:
.block__element#{&}--modifier(用插值),但要注意 Sass 3.4+ 才支持在选择器中插值 - 如果用了
@extend再配合&,可能触发 “You may not @extend an outer selector from within a media query” 类错误,因为&引用的父选择器可能跨了媒体查询边界
在 @media 或 @supports 中使用 & 的限制
& 在媒体查询内部依然有效,但它引用的是**媒体查询外最近的父选择器**,不是媒体查询本身。比如:
立即学习“前端免费学习笔记(深入)”;
.component {
@media (min-width: 768px) {
&__header { font-size: 1.2em; }
}
}
生成的是 @media (min-width: 768px) { .component__header { ... } },不是 .component @media {...}。
- 不能在
@media块里用&引用另一个@media的条件,Sass 不支持嵌套媒体查询的逻辑组合 -
@supports (display: grid)内的&行为和@media一致,但部分旧版 Dart Sass 对@supports+&的解析有 bug,建议升级到 1.40+ - 如果父选择器本身带
:not()或函数式伪类,&拼出的选择器可能被某些浏览器拒绝解析(如.x:not(.y)&:hover是无效语法)
替代 & 的更可控写法:选择器插值 #{}
当 & 的自动拼接逻辑不符合预期时,插值是更透明的方案。它强制你写出完整选择器结构,避免隐式行为带来的歧义。
- 插值必须用引号包裹字符串:
#{".foo"}__bar→.foo__bar;写成#{.foo}__bar会报错 - 变量必须已定义且为字符串类型,
$name: "btn"; #{$name}--active合法,但$name: btn;(无引号)会导致编译失败 - 插值无法参与选择器合并(selector merge),所以
@extend不能跨插值边界工作 —— 这既是限制,也是避免意外继承的保护
复杂组件的样式组织中,& 看似省事,但一旦嵌套超过三层或混用 BEM/状态类/媒体查询,它的“自动展开”反而成了调试负担。真正省心的做法,往往是少依赖 &,多用语义清晰的插值或扁平化结构。










