Dart Sass 不处理 :has()、:is() 等新 CSS 特性,强行在 SCSS 中嵌套使用会因解析失败报错;正确做法是交由 PostCSS(配合 postcss-preset-env)处理,确保构建链为 Sass → PostCSS,且配置 stage: 4。

直接说结论:Dart Sass 本身不处理 :has()、:is() 这类新 CSS 特性,强行在 SCSS 里写会报错或语义错位;真正该负责这事的是 PostCSS,不是 Sass 编译器。
为什么 sass --watch 一碰到 :has() 就报错
Dart Sass 的职责非常明确:把 @use、嵌套、变量这些 SCSS 语法转成标准 CSS 字符串。它不校验输出的 CSS 是否合法,也不解析浏览器才认识的伪类——但问题出在“解析阶段”:当你写 &:has(.badge),Dart Sass 会尝试把 :has(.badge) 当作一个嵌套选择器片段去拼接,而它根本不是 SCSS 语法,所以直接卡在解析器层面,报类似 Invalid CSS after "&:has" 的错误。
- 这不是 Dart Sass “版本低”,升级到
1.77.6或更高也没用 -
:where()、:is()、:has()必须作为完整选择器出现,不能跟在&后面参与拼接 - 若硬要保留嵌套写法,只能写成字符串:
"&:has(.badge)",但此时已失去 SCSS 嵌套的语义和维护价值
PostCSS 才是处理新 CSS 特性的正确位置
你应该让 Dart Sass 输出原始 CSS(含 :has()),再交给 PostCSS 做合法性透传、降级或功能查询支持。关键点在于构建链顺序和配置:
- 确保 PostCSS 在 Sass 之后执行(Webpack/Vite 中 loader 顺序必须是
css-loader → postcss-loader → sass-loader,反过来就失效) -
postcss.config.js中启用postcss-preset-env,且stage: 4(支持所有 CR 阶段特性) - 别在 Sass 里写
@supports (selector(:has(*)))——selector()是 CSS 函数,Dart Sass 会报Undefined function selector - 需要条件编译?改用 Sass 变量:
@if $supports-has { ... },再由构建脚本注入该变量值
Vite / Webpack / VSCode 中常见静默失败点
很多“支持不了新语法”的问题,其实不是工具不支持,而是构建链断在了中间某环:
立即学习“前端免费学习笔记(深入)”;
- Vite 用户:只装
sass不够,必须同时装postcss和postcss-preset-env,否则.scss文件走的是纯 Sass 编译路径,PostCSS 根本没机会介入 - Webpack 用户:检查
rules里sass-loader后是否紧跟着postcss-loader;如果用了MiniCssExtractPlugin,确保它的 loader 配置也包含 PostCSS - VSCode + Live Sass Compiler:这个插件默认绕过 PostCSS,它调的是纯
sassCLI;要支持新语法,必须停用它,改用tasks.json调sass --watch+ 外部 PostCSS 构建流程 - Sublime Text 用户:自定义
.sublime-build只能调sass,同样不经过 PostCSS;想用:has(),就得在终端另起sass --watch src/scss:dist/css && postcss dist/css/*.css -d dist/css/
最易被忽略的一点:所有现代 CSS 伪类都必须出现在最终 CSS 字符串中,而不是 Sass 编译过程中。这意味着你得接受“Sass 输出原始 CSS → PostCSS 接手处理”这个两段式流程,任何试图把两者逻辑揉进一个工具里的做法,都会在某个版本更新后突然崩掉。


















