1. uni.scss解决的痛点一套全局样式变量省掉所有页面里的import做uni-app开发一段时间后大家大概率都会遇到同一个让我很头疼的局面项目里有几十个页面每个页面的style里都飘着一行import ../../styles/variables.scss;路径深浅不一有的页面忘了引导致颜色对不上有的页面引了两份还有的同事直接把颜色值写死在style里改起主题色来像在做考古挖掘。uni.scss就是为了收拾这种局面而存在的。它是uni-app项目里的一个特殊样式文件放在项目的src目录下HBuilderX创建的项目里通常在根目录。这个文件不需要你在组件里手动import编译阶段构建工具会自动把文件内容注入到每个vue组件的style块中。也就是说只要你在uni.scss里定义了$primary-color: #2979ff;全项目的任何组件style里都能直接用这个变量不存在“忘记引入”这种问题。更省心的是uni-app官方在uni.scss里已经内置了一批常见样式变量包括$uni-color-primary、$uni-color-success、$uni-color-warning、$uni-color-error、$uni-text-color、$uni-bg-color、$uni-font-size-sm、$uni-font-size-base、$uni-font-size-lg等等。如果你不覆盖它们你甚至可以直接在组件里用这些变量名。多数实际项目会选择在uni.scss里重新声明同名变量做覆盖把默认品牌色替换成自己的主色调。我个人的感受是uni.scss就是整个项目的“样式总闸”它适合放一切需要跨页面复用的样式token比如品牌色、功能色、字体大小梯度、间距梯度、圆角尺寸、阴影层级、z-index层级。凡是那种“可能在五个页面里出现同一个颜色值”的情况都该进uni.scss。这样以后调整视觉规范时只需要改一个文件而不是满项目替换。另外一个很多人没意识到的好处是在uni.scss里定义变量可以跨平台生效。uni-app编译到小程序、H5、App端时uni.scss的注入逻辑在多个平台构建链路里是一致的所以那些配色、字号、间距的变量在小程序里用同一套在H5里也同一套这比在CSS里写var(--xxx)再手动适配平台要省事得多。2. 自动化注入机制vite与webpack如何在编译期把变量塞进每个style要真正理解uni.scss的“自动全局可用”得先搞清楚构建工具在背后做了什么。我刚接触uni-app时也好奇过为什么vue组件里的style langscss没有写import却能直接使用uni.scss里的变量这背后其实是Sass编译器在编译每个style块之前被额外追加了一段代码。在webpack构建体系主要是vue2版本的uni-app或者cli方式创建的老项目里这个逻辑由sass-loader的additionalData配置实现。你可以把它理解为webpack在处理每个.vue文件的style部分时会在你的SCSS代码前面自动拼接一段import uni.scss;然后再交给sass编译器。所以对你来说像是“变量凭空出现”实际上是构建工具替你做了import。在vite构建体系HBuilderX 3.x版本之后创建的vue3项目里对应的配置点是css.preprocessorOptions.scss.additionalData效果一样也是每次编译scss前自动注入了uni.scss的内容。正因为是“注入”所以它比手动import更隐蔽也更彻底——只要是项目内的vue组件style块全部覆盖不会遗漏。理解这个机制有两个实际价值第一你就明白为什么uni.scss里不能写实际的CSS样式代码。比如你在uni.scss里写了一个.btn { color: red; }由于文件内容会被注入到每一个组件的style里那么每个组件编译后都会携带一份.btn的样式定义重复代码直接膨胀包体。uni.scss应该只放变量、mixin、函数这类“编译期产物”不能放选择器样式。第二如果你用的是cli方式创建的项目想扩展多个全局变量文件可以通过修改vue.config.jswebpack或vite.config.jsvite里的additionalData配置把别的scss文件也追加进去。我自己在维护一个中大型项目时就把uni.scss拆成了uni.scss和_theme.scss两个文件——前者放基础token后者放业务扩展变量因为uni.scss是被构建工具指名注入的所以_theme.scss需要在additionalData里手动补一条import /styles/theme.scss;。如果你在HBuilderX里创建项目基本不需要碰这些配置uni.scss这个约定文件已经被内置的构建配置处理好了。但知道机制仍然有用它决定了哪些事情可以放心做、哪些事情不能做。3. 变量怎么定一套覆盖颜色、字号、间距、rpx换算的uni.scss配置说回正题在uni.scss里定义变量最忌讳的就是东一榔头西一棒槌今天加一个$blue明天加一个$themeColor到最后变量名和值自己都记不住。我建议按类别组织并且定好一套能直接用起来的写法。3.1 颜色体系按“语义”命名而不是按“色值”命名常见做法是把颜色分为品牌色、功能色、文本色、背景色、边框色几类。命名上我推荐$uni-前缀延续官方风格方便与内置变量保持一致。比如品牌主色命名为$uni-color-primary浅一点的辅助色命名为$uni-color-secondary成功/警告/错误这些沿用官方语义名称。值得多说一句的是“文本色”和“背景色”这类变量。很多项目很喜欢直接用$color-white、$color-black看起来直接但一旦视觉改版这种按颜色外观命名的变量就得大量替换。我更倾向用使用场景命名比如$uni-text-color-grey这种它表达的是“灰色文本”的语义而不是“灰色”本质上你是告诉后来人“这里就是给次要文本用的颜色”。语义多过表色后续维护会更省力。3.2 字号、间距、圆角与阴影的梯度设计字体大小我建议参考官方内置梯度$uni-font-size-sm、$uni-font-size-base、$uni-font-size-lg在这个基础上按需增加$uni-font-size-xl、$uni-font-size-xxl。间距系统比较适合做一套8像素基准的梯度$spacing-xs: 8rpx;、$spacing-sm: 16rpx;、$spacing-md: 24rpx;、$spacing-lg: 32rpx;、$spacing-xl: 48rpx;。圆角通用等级可以分成small/medium/large阴影则是轻、中、重三档。有一点在实际项目里经常被我用到在uni.scss里定义变量后可以直接给这些变量补充!default标记。!default在SCSS里的含义是“如果这个变量之前没有被赋值则使用当前值”。这样做的价值在于组件库或者第三方插件里如果也定义了同名变量它们会被你的项目值覆盖而不会反过来把你的覆盖掉。uni-app官方文档里的内置变量大多带!default这也是我们自定义时要保持的习惯。3.3 rpx换算的正确姿势以750设计稿为基准uni-app的rpx规则是“屏幕宽度永远是750rpx”。这带来一个特别方便的换算逻辑如果设计稿是按750px宽做的那么在uni.scss里定义间距和尺寸变量时直接照搬设计稿的px数值写成rpx值就行不需要做任何除法。比如设计稿上边距是32px你就在uni.scss里写$spacing-page: 32rpx;实测下来在大多数设备上渲染效果和设计稿基本一致。这个规则很适合定义一批页面级变量$page-padding: 30rpx;、$card-radius: 16rpx;、$button-height: 88rpx;。把这些写在uni.scss里页面里造组件时顺手就能用不用每个页面都重新换算一遍。需要提醒的是如果项目里会有非750宽度的设计稿比如有的车机屏幕或者特殊大屏场景用的是其他基准那rpx本身的效果会不一致这时候变量方案就要谨慎些。但对常规手机项目来说750基准的rpx加上uni.scss变量是性价比很高的组合。3.4 用SCSS函数做衍生色板比死记硬背色值更高级一点的做法是在uni.scss里用SCSS自带函数衍生颜色。比如定义了主色$uni-color-primary: #2979ff;之后可以顺手生成$uni-color-primary-light: lighten($uni-color-primary, 10%); $uni-color-primary-dark: darken($uni-color-primary, 10%); $uni-color-primary-gradient: linear-gradient(135deg, $uni-color-primary, $uni-color-primary-light);这样做的收益是后续如果品牌主色变了你只需要改一个值浅色、深色、渐变全部同步更新。我在实际项目里维护过三套主题每套只改5个核心色值其余十几二十个衍生变量全部自动生成视觉一致性比手工调色好得多。4. 这些坑我踩过缓存不刷新、样式重复注入与多端差异uni.scss的设计初衷非常好但实际使用中也有几个坑基本都是踩过之后才明白的。4.1 改了uni.scss保存页面样式纹丝不动这个问题在HBuilderX和微信开发者工具的组合环境下尤其容易触发。uni.scss被构建工具注入修改它之后构建工具不一定能完整感知这个间接依赖的变化——尤其是HBuilderX的增量编译机制在极端情况下只会重新编译“发生变化的文件”而uni.scss的变化可能没有正确传播到每个vue文件。我处理这个问题的固定流程是先停掉编译在HBuilderX里选择“重新运行到小程序模拟器”如果还不行就删除项目里的unpackage目录这是编译缓存目录让它全量重新编译。相比之下微信开发者工具侧的缓存很少是根因但它也会缓存过去编译好的js和样式稳妥起见可以把微信开发者工具里的“不校验合法域名”“ES6转ES5”这类设置检查一下排除干扰项。只要你确认uni.scss文件本身保存无误全量重编之后变量一定会恢复生效。这个坑不是代码层面的问题纯粹是缓存和增量编译机制的限制写进项目文档里能帮团队省很多排查时间。4.2 别在uni.scss里写任何真实样式前面提过机制层面的原因——uni.scss会被注入到每个style块所以一旦在里面写.page-title { font-size: 32rpx; }这类选择器样式所有组件编译出来都会带上一份。这在H5端可能不明显在小程序端却会导致wxss文件体积明显增大严重时还会引起样式优先级互相干扰出现“这个页面字体为什么变大了”的鬼畜问题。更隐蔽的坑是很多人会把类似font-face的字体声明、page/body级别的全局样式误放到uni.scss里。页面级全局样式应该放在App.vue的style里uni.scss只承担变量和mixin的职责。这是我强烈建议写进项目规范的一条uni.scss不等于全局样式文件。4.3 dart-sass兼容性import老用法与新语法之间的切换uni-app从早期版本一路迭代过来底层sass编译器版本也在升级。新版uni-app项目默认使用dart-sass它对import的支持开始弱化官方更推荐use。但uni.scss里的变量是“被注入”到组件里的注入之后如果你在uni.scss里写了import去引别的文件旧语法在部分编译环境中会出现“模块化循环依赖”或“找不到变量”的报错。我的建议是如果项目还在用import的写法升级编译器或迁移到新项目时主动把uni.scss里的import换成use或者直接合并文件内容。另外新版dart-sass对lighten()、darken()这类老函数名仍然保留但项目里大量使用它们时要注意编译器版本有些版本会输出deprecation警告虽然不影响运行但还是尽早改掉比较舒服。4.4 小程序端与H5端的CSS变量差异用uni.scss做预编译变量本质上是“编译期间把变量值算好”所以最终产物里没有变量的概念只有具体值。这在小程序端毫无问题因为小程序的WXSS对CSS自定义属性var(--xxx)的支持并不全面尤其是一些老版本基础库动态切换主题时经常失灵。而H5端不同CSS变量是原生能力运行时换肤非常顺畅。这就带来一个设计层面的取舍如果项目只面向H5你甚至可以base在uni.scss之上再抽一层CSS变量实现运行时动态换肤如果项目要同时覆盖小程序和H5最稳妥的方案还是用uni.scss做编译期变量兼顾两端兼容性。我的实际经验是优先用uni.scss变量做整套组件样式等真有换肤需求时再推出基于CSS变量的运行时覆盖层而不是一开始就依赖CSS变量。5. 从单主题到换肤uni.scss在深色模式与主题切换中的定位很多项目到后期都会面临换肤或深色模式的需求。uni.scss在这里的核心定位是“定义所有可换肤的语义token”而不是直接写死具体色值。我在一个做过三套主题的跨端项目里是这么处理的uni.scss里不直接写#2979ff这种具体值而是写$brand-primary: $theme-blue-primary;这样的映射层。三个主题各有一个类似_theme-blue.scss、_theme-red.scss、_theme-dark.scss的文件里面各自定义$theme-blue-primary等具体值。编译时根据打包配置引入对应主题文件// uni.scss $uni-color-primary: $theme-primary; $uni-color-success: $theme-success; // 其余变量类似这样做的好处是组件代码里只跟$uni-color-primary打交道主题切换项目里只需要换一份主题文件并重新编译。对于小程序端运行时切换基础库的CSS变量支持有限所以编译期就生成多套主题包是更稳的方案。深色模式稍微特殊一些。H5端可以借助media (prefers-color-scheme: dark)在运行时做适配但小程序端并没有完全统一可靠的系统深色模式API。我在项目中踩过后发现纯靠uni.scss做深色模式只能编译出深色版本没法跟随系统自动切换。实际的项目方案通常是小程序端在页面里手动加“深色模式开关”编译时生成两套主题样式通过根节点的class切换H5端则额外叠加prefers-color-scheme媒体查询让系统深色模式也能触发。这个阶段uni.scss的角色是“唯一的变量源”。无论主题切换还是深色模式最后映射到的都是这一组语义token上游怎么变组件代码都不用动。6. 多人协作下样式变量的管理建议命名、分层与变更纪律最后聊一点团队协作层面的经验。uni.scss是全局注入的它影响全项目的所有组件所以它也是团队协作中“牵一发动全身”的高风险文件。多人同时改uni.scss经常出现相互覆盖、语义冲突的问题。我目前在项目里推行的规则主要有三点第一变量命名必须带语义前缀。比如$font-开头的都是字号、$color-开头的都是颜色、$spacing-开头的都是间距。这样在组件里看到一个$color-primary-light马上能判断它属于颜色体系且是主色的浅色变体。禁止出现$blue、$size1这类没有语义的命名。第二区分“基础token”和“业务变量”。基础token只管视觉体系颜色、字号、间距、圆角业务变量则可以有页面或模块级别的、带有业务含义的变量。比如首页头部背景色可以定义成$home-header-bg它应该放在单独的_business.scss里不要直接堆进uni.scss。否则uni.scss很快会变成一个大杂烩。第三提交变更要有注释和影响说明。我个人的习惯是如果改动了一个核心色值提交信息里会写明“修改主色以配合新品牌色影响登录页、首页、个人中心共12处组件”并且带一个自查清单——是否影响深色模式、是否需要同步改衍生色、是否影响第三方插件里的同名覆盖。这些看起来琐碎但能避免很多“颜色悄悄变了但没人知道是谁改的”的情况。从工具层面说我还会给uni.scss配置eslint式的stylelint校验加上scss语法校验规则。虽然stylelint对变量名的检查需要自定义规则但至少能拦住$uni-color-primary重复定义这类低级错误。中小团队完全可以做到。这套配合做完之后uni.scss从“一个人维护的样式杂货铺”变成了“全团队共享的视觉规范源”。我在这个项目上花的时间很长但收益也实在明显每次视觉改版基本改几个变量就能完事很少再出现翻遍全项目替换色值的苦差事。