必须用 createGlobalStyle 函数式写法显式接收 theme 参数,否则 props.theme 为 undefined;需解构 theme 并用 ?. 和 || 提供默认值,媒体查询应交由 CSS 原生处理,CSS 变量注入仅在首次挂载时生效。

必须用 createGlobalStyle + 函数式写法显式接收 theme 参数,否则 props.theme 是 undefined。
为什么 createGlobalStyle 里直接写 ${props => props.theme.xxx} 会失效
因为 createGlobalStyle 默认不自动注入 ThemeProvider 的 theme,它不是普通 styled 组件,不会像 styled.div 那样自动把 theme 挂到 props 上。你写的 ${props => props.theme.primary} 实际上访问的是一个未定义的 props.theme,结果是 undefined,最终生成无效 CSS(比如 --primary: undefined)。
- 错误写法:
createGlobalStyle` :root { --primary: ${props => props.theme.primary}; } `→props.theme为undefined - 正确前提:必须把
createGlobalStyle声明为函数,并显式声明参数({ theme }) - 主题对象本身需是纯 JS 对象(支持 TypeScript 接口约束),不能依赖运行时 DOM 查询
怎么安全地把 theme 映射成 :root CSS 变量
核心是函数签名 + 字符串插值组合,确保每个变量都 fallback 到合理默认值,避免渲染空白或报错。
- 显式解构:
createGlobalStyle(({ theme }) => `:root { --primary: ${theme.colors?.primary || '#007bff'}; --bg: ${theme.colors?.bg || '#fff'}; }`) - 别在插值里调用异步函数或副作用逻辑——
createGlobalStyle是同步求值的 - 如果 theme 某字段可能缺失,用可选链
?.+||保底,比如theme.spacing?.md || '0.75rem' - CSS 变量名建议统一前缀(如
--sc-primary),避免和项目其他 CSS-in-JS 库或手写 CSS 冲突
媒体查询中动态切换 CSS 变量要不要走 JS?
不需要。媒体查询响应式切换应交给 CSS 原生能力,JS 只负责初始注入;否则会丢失系统偏好(如暗色模式切换)的实时性。
立即学习“前端免费学习笔记(深入)”;
- ✅ 推荐:
@media (prefers-color-scheme: dark) { :root { --bg: #121212; --text: #e0e0e0; } }—— 浏览器自动响应 - ❌ 避免:
${props => props.theme.isDark ? 'dark rules' : 'light rules'}—— React 渲染时机滞后,且无法监听系统变化 - 可以把媒体查询写在同一个
createGlobalStyle函数返回的字符串里,和 :root 变量共存 - 注意:CSS 变量作用域是级联的,:root 定义后,子元素用
var(--bg)即可继承,无需重复声明
全局变量和组件内插值怎么混合使用
JS 插值用于「组件粒度」的动态控制,CSS 变量用于「跨组件/伪元素/动画」场景,两者互补而非互斥。
- 组件内优先用
${props => props.color || 'var(--text-default)'}—— JS 值优先,fallback 到 CSS 变量 - 伪元素必须用
color: var(--text-primary),${props => props.color}在&::before里不生效 - 动画颜色渐变必须靠
transition: color 0.2s; color: var(--accent);,不能靠 JS 插值重绘 - 想让某个组件覆盖全局变量?在组件根元素加
style={{ '--accent': props.accent }}即可局部重写
真正容易被忽略的是:CSS 变量一旦注入 :root 就是全局生效的,但它的值只在首次挂载时由 createGlobalStyle 计算一次;后续 theme 更新不会自动刷新这些变量——所以 theme 必须是稳定引用(比如 Context 提供的 immutable 对象),或者配合 key 强制重挂载 GlobalStyle 组件。


















