解决在 Next.js 项目中使用 Ant Design 组件时,页面刷新会出现样式错乱和闪烁问题

7 阅读4分钟

🚨 问题描述

原文章链接: avicii13579.github.io/blog/techno…

在 Next.js 项目中使用 Ant Design 组件时,页面刷新会出现样式错乱和闪烁问题,主要表现为:

  • 页面刷新时组件样式丢失
  • 服务端渲染与客户端样式不一致
  • CSS-in-JS 样式注入顺序问题
  • 组件初始化时的视觉闪烁 (FOUC - Flash of Unstyled Content)

💡 解决方案

1. 安装官方 Next.js 集成包

npm install @ant-design/nextjs-registry

2. 更新 src/app/layout.tsx

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import Header from "@/components/shared/Header";
import Footer from "@/components/shared/Footer";
import { ConfigProvider } from "antd";
import { AntdRegistry } from "@ant-design/nextjs-registry"; // 新增

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
  display: "swap",
  preload: true,
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono", 
  subsets: ["latin"],
  display: "swap",
  preload: true,
});

export const metadata: Metadata = {
  title: "法规标准数据库",
  description: "法规标准数据库",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="zh-CN" suppressHydrationWarning>
      <head>
        {/* 预加载关键CSS */}
        <link
          rel="preload"
          href="/fonts"
          as="font"
          type="font/woff2"
          crossOrigin="anonymous"
        />
        {/* 防止样式闪烁和Ant Design FOUC */}
        <style
          dangerouslySetInnerHTML={{
            __html: `
            html { 
              visibility: visible !important; 
              opacity: 1 !important; 
            }
            body { 
              font-family: var(--font-geist-sans), Arial, Helvetica, sans-serif; 
              visibility: visible !important; 
              opacity: 1 !important;
            }
            /* 防止 Ant Design 组件渲染时的样式闪烁 */
            .ant-btn, .ant-input, .ant-select, .ant-table { 
              opacity: 1 !important; 
            }
            /* 确保组件容器立即可见 */
            [class*="ant-"] { 
              visibility: visible !important; 
            }
          `,
          }}
        />
        {/* 防止水合错误 */}
        <script
          dangerouslySetInnerHTML={{
            __html: `
            window.__ANTD_STYLE_CACHE__ = {};
          `,
          }}
        />
      </head>
      <body
        className={`${geistSans.variable} ${geistMono.variable}`}
        suppressHydrationWarning
      >
        <AntdRegistry>  {/* 🔑 关键:使用 AntdRegistry 包装器 */}
          <ConfigProvider
            theme={{
              token: {
                colorPrimary: "#02bb91",
                borderRadius: 4,
              },
            }}
          >
            <Header />
            <div className="mx-auto relative min-h-[calc(100vh-468px)]">
              {children}
            </div>
            <Footer />
          </ConfigProvider>
        </AntdRegistry>
      </body>
    </html>
  );
}

3. 优化 next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  publicRuntimeConfig: {
    apiUrl: process.env.NODE_ENV_API || 'dev',
  },
  
  /**
   * 编译优化
   */
  compiler: {
    removeConsole: process.env.NODE_ENV === "production",
    styledComponents: false, // 🔑 关键:禁用冲突的 styled-components
  },
  
  /**
   * 实验性功能 - 优化CSS
   */
  experimental: {
    optimizeCss: true,
    cssChunking: true, // 🔑 关键:启用CSS分块优化
  },
  
  /**
   * 代理配置
   */
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: `${process.env.API_BASE_URL || 'http://www.api.com/api/prod'}/:path*`,
      },
    ]
  },
  
  /**
   * 图片优化配置
   */
  images: {
    domains: [],
    formats: ['image/webp', 'image/avif'],
  },
};

export default nextConfig;

4. 增强 src/app/globals.css

@import "tailwindcss";

/**
 * 防止样式闪烁的关键样式
 */
html {
  visibility: visible !important;
  opacity: 1 !important;
}

body {
  visibility: visible !important;
  opacity: 1 !important;
}

/**
 * Ant Design 样式稳定性优化
 */
.ant-btn,
.ant-input,
.ant-select,
.ant-table,
.ant-pagination,
.ant-tree,
.ant-checkbox,
.ant-menu {
  /* 防止组件渲染时的闪烁 */
  transition: none !important;
}

/* 确保 Ant Design 组件的基础样式立即可用 */
.ant-btn {
  line-height: 1.5715;
  position: relative;
  display: inline-block;
  font-weight: 400;
  white-space: nowrap;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  user-select: none;
  touch-action: manipulation;
}

.ant-input {
  position: relative;
  display: inline-block;
  width: 100%;
  min-width: 0;
  color: rgba(0, 0, 0, 0.88);
  font-size: 14px;
  line-height: 1.5715;
  background-color: #ffffff;
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  transition: all 0.2s;
}

/* 其他 Ant Design 样式覆盖 */
.ant-pagination-item-active {
  border-color: #02bb91 !important;
}
.ant-pagination-item-active a {
  color: #02bb91 !important;
}

/* 防止水合不匹配导致的样式闪烁 */
[data-nextjs-scroll-focus-boundary] {
  display: contents;
}

🔧 关键解决要点

1. AntdRegistry 包装器

  • 使用 @ant-design/nextjs-registry 提供的 AntdRegistry
  • 确保 CSS-in-JS 样式在 SSR 时正确注入
  • 解决客户端与服务端样式不一致问题

2. 内联样式预防

  • <head> 中添加内联样式防止 FOUC
  • 确保关键组件立即可见
  • 初始化样式缓存对象

3. 配置优化

  • 启用 cssChunking 优化CSS分块
  • 禁用 styledComponents 避免冲突
  • 使用 optimizeCss 实验性功能

4. 全局样式增强

  • 添加 Ant Design 组件基础样式
  • 暂时禁用过渡效果防止闪烁
  • 确保样式加载优先级

✅ 验证方法

  1. 硬刷新测试

    # 清除缓存并刷新
    Ctrl+Shift+R (Windows) / Cmd+Shift+R (Mac)
    
  2. 开发者工具验证

    • 检查 Network 面板中样式加载顺序
    • 确认没有样式加载失败
    • 验证没有控制台错误
  3. 多浏览器测试

    • Chrome、Firefox、Safari
    • 隐私/无痕模式测试

📋 最佳实践

✅ 推荐做法

  1. 始终使用 AntdRegistry

    <AntdRegistry>
      <ConfigProvider>
        {/* 你的应用内容 */}
      </ConfigProvider>
    </AntdRegistry>
    
  2. 保持样式加载顺序

    • globals.css 在最前面
    • 组件样式在后面
    • Ant Design 覆盖样式在最后
  3. 使用 suppressHydrationWarning

    <html suppressHydrationWarning>
    <body suppressHydrationWarning>
    

❌ 避免的做法

  1. 不要移除 AntdRegistry
  2. 不要在 SSR 时动态加载样式
  3. 不要使用 styled-components 与 Ant Design 混用
  4. 不要在组件中使用 useEffect 来修复样式

🚀 效果对比

修复前

  • ❌ 页面刷新时出现白屏
  • ❌ 组件样式逐个加载
  • ❌ 布局跳动和闪烁
  • ❌ 服务端渲染不一致

修复后

  • ✅ 页面刷新样式稳定
  • ✅ 组件立即正确渲染
  • ✅ 无布局偏移
  • ✅ SSR 与客户端一致

📖 相关资源


最后更新时间: 2025年7月

兼容版本:

  • Next.js 15.2.3+
  • Ant Design 5.26.5+
  • React 18.3.1+