Next.js 中 CSS 重复加载的根源是构建管道未识别 SSR 已注入样式,导致客户端二次注入;应确保 CSS 仅在 layout/loading 中引入、升级至 next@14.2+、禁用 @import,并正确使用 styled-components 的 ServerStyleSheet 与 StyleSheetManager。

服务端渲染完成的 HTML 已含样式,客户端再加载一遍 CSS 就会重复注入,导致类名冲突、FOUC 或 Hydration mismatch。关键不是“禁用客户端加载”,而是让客户端跳过已由服务端提供的样式。
Next.js 中 CSS 重复加载的典型表现
在 next dev 或构建后查看 <head>,发现同一 CSS 文件出现两次:footer-abc123.css 和 footer-def456.css;或控制台报 Duplicate module;甚至组件样式闪烁、主题错乱。
- 根本原因常是 Next.js 版本缺陷(如
next@13.4.12、next@14.0.0-rc.0),其css-loader与mini-css-extract-plugin在构建时竞态触发二次注入 - 不是你 import 多了——即使只在
app/layout.tsx中 import 一次,仍可能重复 - 也不是 CSS Modules 配置问题,而是底层构建管道未正确识别 SSR 已输出的样式
styled-components 在 SSR 中如何避免重复注入
它靠 ServerStyleSheet 收集服务端样式并内联进 HTML,客户端则通过 StyleSheetManager 检测已有 <style> 标签,自动跳过重复注入。
- 服务端必须调用
sheet.collectStyles()包裹 React 渲染,并用sheet.getStyleTags()注入到 HTML 的<head> - 客户端必须使用
<StyleSheetManager sheet={sheet.instance}>,否则无法复用服务端生成的mainSheet - 若用 React Server Components(React 19+),无需
use client,styled.div会自动走 RSC 路径,用React.cache管理 sheet,天然避免重复
通用 CSS 文件(非 CSS-in-JS)重复引入的修复逻辑
全局 CSS(如 globals.css)或框架 CSS(如 Tailwind)被重复加载,本质是构建工具未区分“服务端已注入”和“客户端需补全”的场景。
立即学习“前端免费学习笔记(深入)”;
- 确保所有 CSS 只在
app/layout.tsx或app/loading.tsx中 import,**绝不在 Server Component 内 import**(Next.js 不支持) - 升级到 Next.js 官方稳定版(当前推荐
next@14.2.x或更高),执行:npm install next@latest react@latest react-dom@latest并清理缓存:rm -rf .next node_modules/.cache - 禁用
@import方式引入 CSS——它会触发额外请求,且无法被 Webpack/Next.js 构建流程统一去重 - 第三方框架(Bootstrap/Tailwind/Ant Design)的
<link>必须置于<head>最顶部,早于项目自定义样式,否则优先级错乱会掩盖重复问题
真正容易被忽略的是:RSC 环境下 styled-components 的 sheet 重置机制依赖 ensureSheetReset,如果服务端渲染函数没被正确缓存(比如用了未包裹的 async 函数或闭包变量),会导致多次渲染间 sheet 累积,看似“重复”实为污染。这不是配置问题,而是渲染上下文隔离没做好。


















