普通视图

Ant Design v6:zeroRuntime 使用与踩坑总结

2025年12月31日 08:00

React 19 与 Ant Design v6 升级完成后,我明显感觉到页面 CLS(累积布局偏移)性能变差。首屏渲染时样式出现闪烁,组件尺寸直至 JS 执行完毕才最终稳定。这种情况在 Docusaurus 等静态站点中尤为严重。

一开始我尝试通过 CSS 强制锁定组件宽高(min-width / min-height)缓解偏移,但这牺牲了代码的可维护性。为此,我开始尝试 Ant Design 官方提供的 zeroRuntime 方案。

本文记录了我在使用 Ant Design zeroRuntime 过程中遇到的核心问题、踩过的坑,以及最终为什么选择了 「只使用 CSS + 单一主题」 这一方案。

问题根因:Ant Design 的 CSS 并不是完整样式

在排查过程中,我发现了一个关键事实:

antd/dist/antd.css 中大量使用 var(--ant-*)
但这些 CSS 变量并不存在于任何静态 CSS 文件中

原因在于 Ant Design v6 的样式机制:

  • Ant Design v6 默认使用 CSS-in-JS
  • --ant-* 这类 CSS 变量是:
    • 由 JS 在运行时动态注入
    • 而非静态 CSS 中提前定义

对于 Docusaurus 这类预渲染的静态 HTML 来说:

  • 首屏只包含 HTML 结构
  • CSS 变量尚未注入
  • 等 JS 执行完成后样式才完整
  • 因此不可避免地产生 CLS 和样式闪烁

即使已经引入了 antd/dist/antd.css, 只要 CSS 变量依赖运行时注入,首屏 HTML 本身仍然“感知不到完整样式”

zeroRuntime 的设计原理

zeroRuntime 的核心目标非常明确:

在构建阶段生成完整样式,而不是依赖运行时 CSS-in-JS 注入

官方文档对此的描述是: zeroRuntime 会在构建时,根据配置生成一份完整、可直接使用的 CSS 文件

具体表现为:

构建阶段

  • 通过 genAntdCss.mjs(或类似脚本)
  • 基于指定的 theme、token 配置
  • 生成一份完整、静态 CSS

运行阶段

  • 不再生成或注入样式

  • 组件默认假设:

    所有样式已经存在于页面中

这直接带来一个非常重要的结论:

使用 zeroRuntime 后,所有样式相关配置必须在构建期确定

zeroRuntime 下的能力边界(能做 / 不能做)

这是使用 zeroRuntime 必须接受的现实边界。

✅ 可以做的事情

  • 在生成脚本中配置全局 theme
  • 构建阶段生成一套固定主题的 CSS
  • 使用 ConfigProvider 设置 locale(不影响样式)

❌ 不能做的事情

  • 在组件中通过 ConfigProvider 动态设置 theme
  • 使用 theme.useToken()
  • 运行时切换主题色、componentSize 等样式相关 token

一句话总结:

zeroRuntime = 样式在构建期“完全写死”,JS 不再参与样式生成

这并不是限制,而是 zeroRuntime 的设计前提。

cssVar.key 必须完全一致

在启用 zeroRuntime 时,有一个非常容易忽略、但影响极大的配置点:

cssVar: {
  key: "aishort";
}

这个 key 的作用是: 作为 Ant Design CSS 变量的命名空间标识。

⚠️ 必须保证以下两处完全一致:

  1. 生成 CSS 的脚本配置中
  2. 应用主题时使用的配置中

如果不一致:

  • 构建出来的 CSS 变量无法被组件正确命中
  • zeroRuntime 实际上是“未生效”的
  • 页面刷新时会出现:
    • 字体大小闪烁
    • 组件样式先错后对

一个非常简单的判断方法:

刷新页面是否出现样式闪动?

  • 有 → zeroRuntime 没有真正生效
  • 没有 → 样式已经完全静态化

多主题:理论可行,工程上不值得

我曾尝试过生成 浅色 + 深色两套 CSS,并在运行时进行切换。

结论非常明确:

复杂度极高,不值得投入。

主要问题包括:

  • 多套 CSS 同时存在时:

    • 后加载的主题会覆盖前者
  • 即使切换主题:

    • 实际生效的仍然是权重更高的那套变量
  • 为了解决变量覆盖问题:

    • 需要大量人为拆分、加权、隔离
  • 可维护性和可预测性急剧下降

最终结论是:

zeroRuntime 并不适合运行时多主题切换

因此目前站点仅保留 单一深色主题,不再提供主题切换能力。

ConfigProvider 的现实限制

Ant Design v6 提供了大量基于 ConfigProvidertheme.useToken 的定制能力。

但在 zeroRuntime 模式下:

  • 这些能力几乎全部不可用
  • 官方文档中也明确指出:
    • zeroRuntime 仅适用于 构建期确定样式的场景

这意味着:

  • 原本基于 Ant Design 统一主题系统的设计
  • 需要回退到:
    • 写死样式
    • 预编码 token
    • 构建期生成 CSS

本质上,这是一次明确的取舍:

用灵活性,换取首屏性能和样式稳定性

总结

zeroRuntime 并不是一个“无脑开启就能提升体验”的方案,它更像是一个 为静态站点和性能极致优化而设计的工程取舍

它确实解决了:

  • CLS 问题
  • 首屏样式闪烁
  • 运行时样式注入带来的不确定性

但代价同样明确:

  • 主题必须在构建期确定
  • 动态主题能力几乎全部失效
  • 多主题的工程复杂度呈指数级上升

如果你的项目:

  • 是静态站点(如 Docusaurus)
  • 主题风格长期稳定
  • 更看重首屏性能和视觉一致性

那么 zeroRuntime 是值得使用的方案

但如果你需要:

  • 运行时动态主题
  • 高度可配置的设计系统

那么就必须接受 CSS-in-JS 带来的运行时成本, 或者等待 Ant Design 在未来提供更成熟的解决路径。

❌