从node-sass迁移至Sass:Mixin中父选择器&的兼容改造方案
我正在升级Vue技术栈适配Vite(Vite生成的Web代码更高效),之前已经完成过多个项目的升级,但这次碰到了使用Sass的项目。Vite用的是标准Sass而非node-sass,迁移过程中,项目依赖的重度Sass第三方组件库抛出了错误:
[plugin:vite:css] [sass] Top-level selectors may not contain the parent selector "&".
╷
71 │ &.el-select-dropdown.is-multiple
│ ^
╵
对应的代码块如下:
@mixin select($type, $color) { .select-#{$type}.el-select .el-input { .el-input__suffix{ display: flex; align-items: center; } } /* more code goes here */ &.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{ &.select-#{$type}{ color: $color; } } } @include select('default', $default-color); @include select('info', $info-color);
请问:
- 如何重构这段代码以兼容标准Sass?
- 为什么这段代码能在node-sass中正常运行?
为什么node-sass能正常运行?
node-sass依赖的是已停止维护的LibSass,它在语法校验上比官方主推的标准Dart Sass宽松很多,允许一些不符合规范的写法——比如在没有父选择器嵌套上下文的顶层位置使用&。这种写法本质上违反Sass语法规则,LibSass只是做了妥协性兼容,而标准Sass严格遵循规范,因此直接抛出错误。
代码重构方案
错误核心是&.el-select-dropdown.is-multiple处于mixin顶层,无父选择器上下文,标准Sass不允许这种用法。以下是两种可行的重构方案:
方案1:明确选择器层级(推荐)
原代码的意图是给带.select-{$type}类的多选下拉选中项设置颜色,直接去掉顶层的&,改为明确的选择器组合即可:
@mixin select($type, $color) { .select-#{$type}.el-select .el-input { .el-input__suffix{ display: flex; align-items: center; } } /* more code goes here */ // 替换顶层&为明确的类选择器,保持原样式逻辑 .select-#{$type}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{ color: $color; } } @include select('default', $default-color); @include select('info', $info-color);
方案2:嵌套到父选择器上下文
如果原代码的&是想继承mixin调用处的上下文(当前代码场景下无此需求),可以将代码包裹到一个全局父选择器中,为&提供合法上下文:
@mixin select($type, $color) { .select-#{$type}.el-select .el-input { .el-input__suffix{ display: flex; align-items: center; } } /* more code goes here */ // 用全局根选择器包裹,让&拥有合法的父上下文 :root { &.select-#{$type}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{ color: $color; } } }
方案1完全匹配原代码的样式意图,同时完美兼容标准Sass。
内容的提问来源于stack exchange,提问作者Skaman Sam

