:is() 不能精简嵌套,仅是运行时选择器合并语法;Sass/Less 旧版本不识别会报错或静默丢弃,新版本也仅限顶层使用,嵌套中需用插值 #{} 安全输出,且浏览器兼容性有限。

:is() 本身不能“精简嵌套”,它只是合并多个选择器的运行时语法;预处理器(Sass/Less)不负责解析它,也不参与嵌套逻辑优化——想靠 :is() 减少嵌套层级,会踩坑。
为什么直接在Sass/Less嵌套里写 :is() 很容易失效
预处理器在编译阶段看到 :is(ul, ol) li,旧版 Sass(如 Node Sass)直接报 Invalid CSS after "": expected "{", was ":is(";Less v4.0 及更早版本则可能静默丢弃整条规则,连警告都没有。这不是你写错了,是工具链根本不认识这个语法。
- Sass v1.33+(Dart Sass)才开始识别
:is(),但仅限顶层或简单上下文;一旦嵌套在&:hover或@media内,仍可能解析错乱 - Less v4.1+ 需关闭严格模式(关键是禁用
javascriptEnabled),否则选择器校验失败就跳过 - 所有版本的 Sass/Less 都不支持在
&后动态拼接:is(),比如&:is(.a, .b)是非法的,&只能接伪类(&:hover)、属性(&[data-x])或子选择器(& > li)
Sass 中安全使用 :is() 的唯一推荐方式:插值 #{}
用字符串插值绕过预处理器解析,是最稳、兼容性最好的方案。它不改变语义,也不依赖版本,编译后就是原样输出的 CSS。
- ✅ 正确:
&:hover, #{':is(ul, ol) li'}:focus { color: blue; } - ❌ 错误:
&:hover, :is(ul, ol) li:focus { ... }(旧 Sass 报错;新 Sass 虽编译过,但&的上下文可能被错误继承) - ⚠️ 注意:
#{}里不能含变量插值,比如#{':is(#{$list}, p) li'}会导致 Sass 提前求值并报语法错误 - ? 场景建议:只在需要合并「结构不同但样式相同」的选择器时用,例如按钮和链接都需 focus 样式:
button:focus, a:focus, #{':is([role="button"], [data-action])'}:focus { outline: 2px solid #007bff; }
Less 中启用 :is() 必须关掉选择器校验
Less 默认会对选择器做轻量语法检查,:is() 会被当成非法结构直接忽略——不是报错,而是规则消失,极难排查。
立即学习“前端免费学习笔记(深入)”;
- ✅ 必须配置:
math: always(非关键)、strictUnits: false(非关键),真正起作用的是确保没启用javascriptEnabled: true,且不要在plugins中注入干扰选择器解析的插件 - ✅ Less v4.2+ 可直接写:
.nav { :is(ul, ol) li { margin: 0; } },但注意:这仍是顶层写法,&不支持后缀:is() - ❌ 避免嵌套写法:
ul { li { &:is(.active, .disabled) { ... } } }—— Less 完全不认这种结构,会整个块失效 - ? 兼容性提醒:即使 Less 编译成功,
:is()的浏览器支持仍是硬门槛(Chrome 105+/Firefox 103+/Safari 15.4+),IE 和旧 Edge 全挂
真正该精简的不是选择器,而是嵌套结构本身
很多人想用 :is() 来“拯救”过度嵌套的 Sass/Less,这是方向反了。:is() 解决的是「运行时选择器复用」,不是「源码可维护性」。真正混乱的嵌套,应该靠重构解决:
- 把深层嵌套(如
.card { .header { .title { ... } } })拆成扁平 BEM 命名:.card__title - 用
@mixin或.class-name占位符统一控制多处样式,而不是靠&层层钻 - 警惕
@extend引用含:is()的选择器——Sass 旧版本会崩溃,新版本也可能生成冗余 CSS - 如果项目要长期维护,优先考虑用现代 CSS(
:is()+:where()+:has())替代预处理器嵌套,而非在预处理器里硬塞原生语法


















