SCSS环境变量条件编译:生成多平台差异化CSS
许多开发者在 uni.scss 文件中编写条件编译指令(如 #ifdef)时,发现指令完全不起作用。明明在 .vue 文件中可以正常使用的条件编译,到了 uni.scss 里却失效了。这一困惑的根源并不在于配置错误,而在于 uni.scss 本身不支持条件编译机制。该文件在 uni-app 构建流程
许多开发者在 uni.scss 文件中编写条件编译指令(如 #ifdef)时,发现指令完全不起作用。明明在 .vue 文件中可以正常使用的条件编译,到了 uni.scss 里却失效了。这一困惑的根源并不在于配置错误,而在于 uni.scss 本身不支持条件编译机制。该文件在 uni-app 构建流程中被当作一个纯粹的 SCSS 源文件提前处理,条件编译指令在构建系统介入解析之前就已经被跳过。

uni-app 中 uni.scss 条件编译失效的深层原因
要理解这一现象,需要先明确 uni-app 条件编译的生效范围。条件编译仅在 .vue 文件的 、、 这三个模板块内有效。而 uni.scss 会被 SCSS 预处理器(如 sass)单独读取并编译,这一处理步骤发生在 uni-app 构建系统进行条件解析之前。因此,即使在该文件中写上条件编译指令,最终输出的也只是简单的变量覆盖——例如,以下代码:
// uni.scss /* #ifdef MP-WEIXIN */ $primary-color: #07c160; /* #endif */ /* #ifdef H5 */ $primary-color: #1890ff; /* #endif */
实际编译后得到的结果仅为最后的赋值 $primary-color: #1890ff,前面的声明被完全覆盖,条件编译指令形同虚设。
推荐方案:@import + 条件编译替代全局变量注入
正确的做法是将条件编译的“决策点”放在它能生效的地方——组件的 标签中,尤其是 App.vue 这个全局入口。具体操作分为两步:
- 首先,为不同平台创建独立的变量文件,例如
styles/vars-weixin.scss、styles/vars-h5.scss,在每个文件内分别定义$primary-color等变量。 - 然后,在
App.vue的块中,利用条件编译按需导入:
这样一来,变量定义发生在条件编译生效的上下文中。每个平台仅加载属于自己的变量文件,避免变量污染,逻辑清晰且易维护。
进阶方案:通过 define 注入构建时环境变量给 SCSS
对于熟悉构建流程的开发者,还可以采用更“工程化”的途径:通过构建工具(如 Vite 或 Webpack)将平台环境变量注入到 SCSS 中,然后在 SCSS 内部使用 @if 进行条件判断。以 Vite 为例,流程如下:
- 在
vite.config.ts中,通过define配置项注入一个全局常量,例如:define: { '__PLATFORM__': JSON.stringify(process.env.UNI_PLATFORM) }。 - 借助插件(如
vite-plugin-sass-globals或自定义 loader),将该常量转换为 SCSS 的全局变量(例如$platform)。 - 随后可以在任意 SCSS 文件中使用
@if进行条件判断:
@if $platform == 'mp-weixin' {
$primary-color: #07c160;
} @else if $platform == 'h5' {
$primary-color: #1890ff;
}
该方案有一定门槛,需要完整配置构建插件链,并且必须确保 $platform 变量在所有样式文件被导入(@import)之前就已定义,否则下游文件无法读取该变量。
核心认知:uni.scss 不是条件分发的决策中心
问题的本质在于对 uni.scss 的定位存在偏差。它的作用仅是一个“统一的样式导入点”,而非“条件分发的决策中心”。其内容会无差别地合并到所有平台的最终样式流中,任何在其中尝试逻辑分支的写法,从架构层面就注定失败。真正需要实现样式差异化的逻辑,必须置于条件编译能够触达的位置:组件级的 块、按条件导入的独立 SCSS 文件,或构建配置层面的注入。请注意,SCSS 变量一旦被重复声明,后声明的总会覆盖前声明——它本身缺乏作用域隔离与运行时的判断能力。将平台差异的逻辑交给它处理,自然无法达到预期效果。
