原生css嵌套中,&:hover或&:focus是正确写法,&必须紧贴伪类、不可有空格;漏写&会全局匹配,加空格则变为后代选择器;&仅绑定最近父选择器,多层嵌套不穿透,跨层响应需用:has()配合。

原生 CSS 嵌套中 & 怎么配合伪类写 hover/focus?
原生 CSS 嵌套(CSS Nesting Module)里的 & 不是 SCSS 那套预处理器逻辑,它只在嵌套规则内部生效,且必须显式出现才能复用父选择器。写 &:hover 是最直接、也最安全的方式——编译后就是父选择器 + 伪类的组合,比如 .btn:hover。
常见错误是漏掉 &,直接写 :hover,结果变成全局 :hover 匹配所有元素;或者误加空格写成 & :hover(带空格),那就变成后代选择器,语义完全变了。
-
&:hover→ 正确:作用于当前父选择器自身 -
:hover→ 错误:脱离上下文,匹配任意可 hover 元素 -
& :hover→ 错误:变成“父元素内的任意 hover 元素”,不是你想控制的那个 -
&::before、&[disabled]同理,都支持,但必须紧贴&,不能有空格
& 在多层嵌套里只绑定最近一层父选择器
原生嵌套不支持跨层引用,& 永远只指代它所在规则块的直接父选择器。比如你在 .card { .header { &::after {} } } 里写 &::after,生成的是 .card .header::after,不是 .card::after。
想让 .header 的伪元素影响 .card 自身?原生嵌套做不到。这时候得换思路:要么把样式提到 .card 层级写,要么用 :has() 配合其他状态做条件判断,或者干脆放弃纯 CSS,交由 JS 控制 class。
- 嵌套层级越深,
&的作用域越窄,别指望它“穿透”上去 - 没有
&^或&^^这种语法,浏览器不认 - 如果需要父级响应子级状态,
.parent:has(.child:hover)是目前唯一原生可行路径
和 :has() 混用时,& 位置决定匹配主体
:has() 本身是个伪类,可以和 & 共存,但顺序和位置很关键。例如 .trigger { &:has(+ .target):hover { … } } 是错的——& 必须紧跟在选择器开头,不能插在中间。正确写法是 .trigger:has(+ .target):hover { … },然后在里面嵌套子规则时再用 &。
更典型的是用 :has() 做父级条件判断,再用 & 定义其内部状态样式:
.card {
background: #f8f9fa;
&:has(.status-error) {
border-color: #dc3545;
}
&:has(.status-error) .message {
color: #dc3545;
}
}
注意第二段里的 &:has(...) 中 & 是必须的,否则 :has() 就没主语了。
浏览器兼容性现实:别在生产环境无脑用 & 嵌套
原生 & 嵌套目前仅 Chromium 120+ 和 Safari 17.4+ 稳定支持,Firefox 仍需手动开启实验性 flag(layout.css.nesting.enabled)。这意味着:如果你项目要兼容旧版 Edge、微信内置浏览器或部分安卓 WebView,& 写法会直接被忽略,样式丢失。
- 上线前务必查 caniuse.com 上
css-nesting的实际覆盖数据 - SCSS/PostCSS 用户别混淆:预处理器的
&编译后就没了,和原生运行时行为无关 - 真要用,建议搭配
@supports (selector(:is(*)))做特性检测降级,而不是靠 UA 判断
最易被忽略的一点:原生嵌套的 & 不支持字符串拼接或动态计算,它只是个静态占位符。想实现 BEM 风格的 &--active?可以;想根据变量生成 &[data-mode="dark"]?不行——那得靠 JS 注入 class 或属性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











