推荐在大型项目中使用 CSS 预处理器引入全局变量,因其支持编译期计算(如 darken、数学运算)、跨文件复用、模块化作用域隔离、tree-shaking 优化及 reliable 的 Vite additionalData 注入机制。

大型项目中推荐用 CSS 预处理器引入全局变量,不是因为“更酷”或“更现代”,而是原生 CSS 的 --custom-property 在构建时不可计算、运行时不可复用、作用域难收敛——它解决不了变量跨文件复用、颜色函数调用、@media 值复用这些硬需求。
原生 CSS 变量无法参与编译期计算
原生 --color-primary 只能在运行时被 var() 读取,不能用于 lighten()、scale-color() 或 $spacing-unit * 2 这类运算。Sass 的 $primary-color 是编译期值,可直接参与所有数学和颜色函数:
.btn {
background-color: $primary-color;
border-color: darken($primary-color, 10%);
padding: $spacing-unit * 2;
}- 你没法对
var(--primary-color)调用darken(),浏览器不认这个函数 - 媒体查询断点也必须硬写
@media (min-width: 768px),无法用@media (min-width: $breakpoint-md)抽离复用 - 构建工具(如 Vite)无法在打包时剔除未使用的变量,而 Sass 的
@use支持 tree-shaking
预处理器全局变量能真正隔离作用域
原生 :root 下的 --x 是全局污染的,任何 JS 动态设置都可能意外覆盖组件样式;Sass 的 @use "variables" as vars 或 as * 是模块级作用域,且默认私有:
-
@use导入的变量不会自动泄漏到其他模块,除非显式as *或as foo - 同一变量名在不同
@use模块中互不干扰,比如_button.scss和_card.scss都可以定义$border-radius,彼此独立 - Less 的
@import (reference)更进一步:只提供 mixin/变量,完全不输出 CSS,彻底避免样式泄漏
Vite 中 additionalData 注入才是可靠方案
很多人试图在每个 <style lang="scss"> 里手动 @use,结果 scoped 组件报 Undefined variable——根本原因是变量没在编译器读取组件样式前就位。
立即学习“前端免费学习笔记(深入)”;
-
css.preprocessorOptions.sass.additionalData是唯一能确保所有<style>(含scoped)都能访问变量的机制 - 字符串末尾必须带
\n,否则会和组件第一行样式连成一句,触发Invalid CSS after "" - 路径必须真实存在:
@/styles/variables.scss依赖 Vite 的resolve.alias配置,否则得用path.resolve(__dirname, 'src/styles/variables.scss') - 别在
additionalData里写@import "xxx" as x,Sass 会直接报错;@use也需避开@forward冲突
真正容易被忽略的点是:预处理器变量不是“加个语法糖”,它是把样式逻辑从运行时挪回构建时的关键分水岭——一旦你开始用 darken($color) 或 @each 生成状态类,你就已经依赖编译期能力了,这时候再退回去靠 JS 操控 style.setProperty,只会让逻辑散落、难以测试、无法 SSR。


















