& 本身不处理状态切换,仅展开外层选择器;控制激活态需组合写法与明确层级意图,否则编译选择器无法匹配目标元素。

直接说结论:& 本身不处理“状态切换”,它只是把外层选择器原样展开;真要控制激活态(如 :hover、:focus、.is-active),得靠组合写法 + 明确的层级意图,否则编译出的选择器根本不会匹配目标元素。
为什么 &:hover 编译后没生效
常见现象是写了 .btn { &:hover { color: red; } },但鼠标悬停没反应。原因往往不在 Sass,而在最终 CSS 是否被浏览器执行:
- 父容器没设置
cursor: pointer,iOS Safari 或某些安卓 WebView 下:hover不触发 - 元素被
pointer-events: none挡住,或者父级用了display: none或visibility: hidden - Sass 编译时变量未定义或
@if条件为 false,整段规则被跳过——务必用 DevTools 查看实际生成的 CSS - 写了
&:hover { &__icon { ... } },结果生成.btn:hover__icon(非法选择器),正确写法是&__icon:hover或单独嵌套&__icon { &:hover { ... } }
& 怎么配合 .is-active 类实现切换逻辑
状态类不是伪类,不能靠 &.is-active 自动“监听”变化;它只负责生成静态选择器,JS 控制类名增删才是切换动作本身:
-
.nav { &__item { &.is-active { background: #007bff; } } }→ 编译为.nav__item.is-active,匹配的是「同时拥有两个类的同一个元素」 - 别写
&.is-active &__link,这会生成.nav.is-active .nav__link,语义变成「父有 active 类时子 link 才变样式」,和本意不符 - 多个状态共存(如
.btn.is-active.is-loading),必须连写&.is-active.is-loading,空格或拆成两个&都会导致编译失败或选择器错位 - 若需「父 active 时子元素 hover 变色」,得显式写
&.is-active &__trigger:hover→.nav.is-active .nav__trigger:hover
伪类批量生成:用 @each + & 避免手写重复
手动写 .btn:hover、.btn:focus、.btn:active 太累,Sass 可以用 @each 统一管理,但必须注意顺序和语法:
立即学习“前端免费学习笔记(深入)”;
- 状态列表建议按 LVHA(
:link、:visited、:hover、:active)顺序定义,确保层叠逻辑不出错 - 正确写法:
@each $state in (hover, focus, active) { &:#{'.' + $state} { opacity: 0.8; } }→ 生成.btn:hover、.btn:focus等独立规则 - 别用字符串拼接伪类:
&:#{$state}是合法的,但&:#{'hover:focus'}会产出无效的.btn:hover:focus,浏览器可能忽略 - 禁用态要单独处理:
&:disabled优先级高,且会覆盖其他伪类,所以通常得写在最后,并显式重置样式:&:disabled { cursor: not-allowed; opacity: 0.5; }
容易被忽略的兼容性与性能点
看似简单的状态切换,在跨浏览器和响应式场景下很容易翻车:
-
:focus-visible在 Firefox 和新版 Chrome 中才稳定支持,旧项目仍需 fallback 到:focus,但要注意键盘聚焦和鼠标点击都触发,可能造成误样式 - 移动端不要依赖
:hover做核心交互反馈,iOS Safari 默认只对<a></a>和<button></button>生效,其他元素必须加cursor: pointer才能激活 - 用
:has()实现「子 hover 时父变色」虽简洁,但 Chromium 105+、Firefox 121+、Safari 15.4+ 才支持,IE 和旧版 Android WebView 完全不认,别当主力方案 - Sass 编译期无法感知运行时状态,所以
$state: 'loading'这种变量不能插进选择器(&.is-#{$state}会报错),状态类名必须静态写出或由 JS 动态控制


















