React Native 没有 DOM,没有 CSS 引擎,因此 Web 上常用的 :root / .dark CSS 变量方案在 RN 中完全无效。NativeWind v4 提供的 vars() API 是 RN 环境下实现 CSS 变量的唯一方式——它在 JS 层创建变量绑定,作为 style prop 传给根 View,子组件的 var(--color-xxx) 引用才能解析到实际色值。
为什么 CSS 变量在 RN 不工作
Web 上的暗色模式通常这样实现:
:root { --color-bg: #ffffff; }
.dark { --color-bg: #0f0f0f; }
这依赖浏览器的 CSS 引擎:解析选择器、匹配 DOM 节点、级联变量。RN 没有这些——RN 的”样式”是 JS 对象,由 Yoga 布局引擎处理,不经过 CSS 解析器。
NativeWind vars() 的工作方式
import { vars } from 'nativewind'
const themes = {
light: vars({ '--color-bg': '#faf9f6', '--color-surface': '#ffffff' }),
dark: vars({ '--color-bg': '#0f0f0f', '--color-surface': '#1a1a1a' }),
}
// 根 View 注入变量,所有子组件的 className="bg-bg" 会解析到对应色值
<View style={[{ flex: 1 }, themes[colorScheme]]}>
{children}
</View>
vars() 把 CSS 变量名→值的映射转成 RN style 对象。NativeWind 的 Metro 插件在编译期把 bg-bg 解析为 var(--color-bg) 引用,运行时通过 React 的 style 继承链向下传递。
MindGym 的三次迭代
- useColorScheme sync — 只切换了 NativeWind 的
colorSchemeprop,但 Tailwind 的bg-surface等类名指向固定色值,不会跟着变。 - CSS 变量
:root/.dark— 写进global.css,Metro 编译通过但运行时无效——RN 没有 DOM 来匹配这些选择器。 - vars() API — 在根 View 的 style 中注入变量对象,子组件的
var(--color-xxx)正确解析。
注意事项
- 原生导航组件(Tab 栏、Stack header)不走 NativeWind 的 className,需要直接传 style prop 的色值。
StatusBar的style也需要手动跟随主题:暗色背景用'light'(浅色文字),反之亦然。
参见
- NativeWind 与 Tailwind 设计哲学 — NativeWind 编译原理
- React Native 新架构概览 — JSI 基础
参考
- NativeWind v4 vars() 文档
- MindGym
app/_layout.tsx— buildThemeVars() 实现