动态CSS变量必须定义在:root或html下才真正全局生效;推荐单独创建variables.css文件并在main.ts顶部导入,避免在App.vue scoped style中定义,且不可与Sass/Less变量混淆。

动态CSS变量必须定义在 :root 或 html 下才真正全局生效
UnoCSS 本身不接管 CSS 变量的运行时作用域,它只负责生成原子类或注入预设变量。如果你在 App.vue 的 <style scoped> 里写 :root { --color-primary: #3b82f6 },H5 端可能勉强工作,但微信/支付宝小程序会直接忽略——因为 scoped style 被编译器隔离,:root 失去根上下文意义。
正确做法是单独建 src/styles/variables.css,内容为:
:root {
--color-primary: #3b82f6;
--spacing-xs: 0.25rem;
--radius-sm: 0.125rem;
}然后在 main.ts 最顶部(早于 import "virtual:uno.css")导入:
import '@/styles/variables.css'
- 不能放在
App.vue的<style>块里(哪怕去掉scoped):uni-app 小程序端不认 - 不能用 Sass/Less 变量(如
$primary)替代:它们编译期就消失了,JS 无法读取或修改 - 避免在
@media内重复定义:root:部分旧版 WebView 不支持嵌套重定义,改用html.dark :root更稳
presetWind4 的 preflights 选项能按需输出 CSS 变量层
UnoCSS 的 @unocss/preset-wind4 内置了三层前置样式:reset、theme(即 CSS 变量)、property(@property 声明)。你不需要手动写 :root,只要启用 preflights: { theme: true },它就会自动生成完整 Tailwind 4 风格的变量体系。
立即学习“前端免费学习笔记(深入)”;
配置示例:
import { defineConfig, presetWind4 } from 'unocss'
<p>export default defineConfig({
presets: [
presetWind4({
preflights: {
reset: true,
theme: true, // ← 关键:开启此选项才会输出 --color-<em>, --spacing-</em> 等变量
property: false // 暂不需 CSS 类型校验可关掉
}
})
]
})- 变量名与 Tailwind 4 官方完全对齐(如
--spacing-4对应1rem),不是 UnoCSS 自创命名 - 若你已自定义了
:root,且启用了theme: true,两者会共存——注意变量覆盖顺序:后加载的 CSS 会覆盖先加载的 - 关闭
theme后,bg-blue-500这类类名仍可用(颜色值被内联进原子类),但你无法用var(--color-blue-500)在 JS 或自定义 CSS 中复用
用 rules + 正则动态生成带变量的原子类
想让 bg-var-primary 这种写法生效?UnoCSS 默认不支持 var() 解析,但你可以用 rules 手动桥接:
rules: [
[/^bg-var-(.+)$/, ([, varName]) => ({
'background-color': `var(--${varName})`
})],
[/^text-var-(.+)$/, ([, varName]) => ({
'color': `var(--${varName})`
})]
]这样写 <div class="bg-var-primary text-var-secondary"> 就能绑定到你定义的 --primary 和 --secondary 上。
- 正则捕获组必须用数组解构(
[, varName]),第一个元素是完整匹配字符串,跳过即可 - 不要试图在
rules里写var(--x, fallback):UnoCSS 不解析函数,只当字符串原样输出,浏览器会报错 - 如果变量名含连字符(如
--brand-red-500),正则要允许-:/^bg-var-(.+)$/足够,但更安全可写/^bg-var-([a-z0-9-]+)$/
JS 动态修改变量时,document.documentElement.style.setProperty 是唯一可靠路径
UnoCSS 生成的 CSS 是静态的,运行时切换主题只能靠 JS 修改 :root 变量。别用 document.querySelector(':root').style——:root 不是真实 DOM 元素,查不到。
正确写法:
// 切换主题
document.documentElement.style.setProperty('--color-primary', '#ef4444')
document.documentElement.style.setProperty('--bg-surface', '#1f2937')
<p>// 清除变量(恢复为 :root 中定义的初始值)
document.documentElement.style.removeProperty('--color-primary')- 必须等 DOM 加载完成再执行,
mounted不一定够,尤其在 SSR 或 uni-app 中,建议加setTimeout(() => {}, 0)或监听DOMContentLoaded - 在 uni-app 微信小程序中,基础库 < 2.25.0 时
getPropertyValue返回空字符串,setProperty却仍有效——所以设值没问题,读值要降级 - 频繁设多个变量时,不要循环调用
setProperty:触发多次重排。改用setAttribute('data-theme', 'dark')+ CSS 层级控制更高效
最易被忽略的一点:CSS 变量的继承性与作用域是两回事。你在 :root 设的变量,子元素能用 var() 读取,但如果你在某个组件内又写了 div { --color-primary: red },那这个 div 及其后代读到的就是 red——UnoCSS 不干涉这个过程,它只管“怎么把类名转成 CSS”,剩下的全是浏览器原生规则。


















