Sass 的 & 不是真正的父选择器,因为它仅在编译期静态拼接直接父选择器字符串,不感知 DOM 结构、不支持运行时向上查找;写 .card { .badge { &.is-new { } } } 仅生成 .badge.is-new,无法影响 .card;实现类似 :has() 的效果必须依赖现代 CSS 或 JS,Sass 无能为力。
& 不能“引用父级元素”,它只拼接父级选择器字符串——编译期静态行为,和 DOM 无关。
Sass 的 & 在编译时就被替换成外层选择器的完整字符串,不感知 HTML 结构,也不支持运行时向上查找。写 .card { .badge { &.is-new { ... } } },输出的是 .badge.is-new,不是 .card 变色——它根本没触达父级元素。
想实现类似 :has() 的效果(比如“当内部有 .error 时让 .form 变红”),必须用现代 CSS(Chrome 105+、Safari 15.4+)或 JS,Sass 无能为力。
& 永远只绑定直接父选择器,不会冒泡、跳级或跨嵌套层级.card .header)被 & 展开后仍带空格,生成 .card .header:hover,这常导致意外的后代匹配.btn:not(.disabled)),&__icon 会产出非法选择器:.btn:not(.disabled) .btn:not(.disabled)__icon,浏览器直接拒解析BEM 要求扁平类名(如 .block__element),但直接嵌套 &__element 会产出带空格的后代选择器(.block .block__element)。唯一安全路径是脱离嵌套流:
立即学习“前端免费学习笔记(深入)”;
.block { @at-root #{&}__element { color: blue; } } → 输出 .block__element { ... }
&__element 内部再嵌 &--modifier,那会变成 .block__element--modifier,语义错误@at-root #{&}--hovered,而非嵌套在元素块里#{&} 必须加引号包裹,且仅 Dart Sass 3.4+ 支持选择器内插值& 在媒体查询或 @supports 内依然有效,但它引用的仍是**外部最近的父选择器**,不是媒体查询本身:
.component { @media (min-width: 768px) { &__header { font-size: 1.2em; } } } → 输出 @media (min-width: 768px) { .component__header { ... } }
@media 块里单独写 &,必须配合父选择器上下文,否则报错 Invalid CSS after "&": expected selector
&:before 和 &::before 效果不同:后者才符合现代伪元素规范,前者可能被某些浏览器忽略所有看似“提升”的技巧(比如 @at-root #{&}__item)本质都是字符串重组,和 DOM 层级毫无关系。你无法靠缩进或嵌套结构推断最终 CSS 是否合理。
真正可靠的做法只有两个:
.block .element 这类带空格的后代选择器& 字符串(如 .block__item__icon),那是误用了嵌套层级只要看到编译结果里出现意料之外的空格、多余层级或非法字符,说明 & 已经脱离控制——它从来就不是智能变量,只是个精准但冷酷的字符串锚点。