&是scss编译时占位符,静态替换为外层选择器字符串,确保父子绑定不脱节;手写类名易因组件改名导致全局漏替,而&自动同步更新,避免样式断裂。

为什么直接写 &.is-active 而不是 .btn.is-active
因为 & 是编译时占位符,它静态替换成外层选择器字符串,确保父子绑定不脱节。比如你在 .btn 块里写 &.is-active,编译后一定是 .btn.is-active;如果手写 .btn.is-active,后续组件改名(比如改成 .c-button)就得全局搜替换,漏一处就断样式。
常见错误包括:
- 漏掉
&,写成.is-active .btn__icon→ 编译后变成全局匹配,可能污染其他组件 - 多打空格,写成
& .btn__icon→ 编译为.btn .btn__icon,失去状态约束 - 混用命名风格,父级用
.c-card--hover,子规则却写&.is-hover→ 编译出的类名对不上,样式永不生效
& 必须作为选择器第一个字符,但能接哪些东西
& 后面只能紧跟伪类(如 :hover)、伪元素(如 ::before)、BEM 后缀(如 __icon、--disabled),或组合符(如 +、~、>)。不能跟空格,也不能放在中间。
合法写法示例:
.card {
&__title { font-size: 1.5em; } // → .card__title
&--featured { border: 2px solid gold; } // → .card--featured
&:hover { transform: scale(1.02); } // → .card:hover
& > .card__body { padding: 1rem; } // → .card > .card__body
}
非法写法示例:
-
& .btn__text(带空格)→ 编译为.btn .btn__text,脱离状态上下文 -
.btn__text &(&不在开头)→ Sass 编译报错 -
&:not(:hover)(虽语法合法但极少用,且易读性差)→ 建议拆成独立规则
嵌套状态块时,如何避免层级过深和选择器爆炸
超过三层嵌套(例如 &.is-loading .item .item__inner span)会导致生成的选择器冗长、难以调试,也增加 CSS 文件体积。Sass 不会优化选择器长度,它只是字符串拼接。
推荐做法:
- 把状态块统一放在基础样式之后,视觉上隔离,方便定位:
&.is-active、&.is-disabled等集中收尾 - 一旦发现嵌套路径含两个以上
__或--,考虑抽成独立 BEM 元素(如.btn__spinner单独定义,而非&.is-loading .btn__spinner) - 媒体查询中慎用
&:比如@media (min-width: 768px) { &.fixed { ... } }是安全的;但@media (...) { & .btn__label }就容易误写成脱离状态约束
为什么不能用 :is() 或 :where() 替代 & 实现状态控制
因为 :is() 是运行时 CSS 逻辑,它不感知组件边界。你写 :is(.btn.is-active) .btn__icon,浏览器会在整个 DOM 树里找所有匹配 .btn.is-active 的节点,哪怕那个节点根本不在当前组件内,样式也会生效——这违背了组件封装原则。
& 的作用域是纯静态的、编译期确定的,它只属于当前 SCSS 块的父选择器。这是两者本质区别:一个靠浏览器运行时匹配,一个靠构建工具编译时生成。
真正容易被忽略的一点是:Sass 编译后输出的 CSS 文件里,你必须肉眼确认每条规则是否以组件根类名开头(如 .btn.is-active),而不是 .is-active 或 .btn .btn__icon。只要没验证编译结果,就等于没真正用对 &。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











