Next.js 14 中 styled-components 报错的根本原因是 SSR 水合不一致:服务端未注入样式导致 缺失 标签,客户端 hydration 时 className 不匹配(如 "sc-bdVaJa" vs "sc-gsDKAQ"),触发强制重渲染;而 styled-jsx 因构建期静态解析并内联样式,天然支持 SSR,无需额外配置。

Next.js 14 中用 styled-components 或 emotion 直接报错,根本原因是 SSR 水合不一致(hydration mismatch)或样式未注入首屏 HTML,不是库本身坏了,而是没按 Next.js 的执行时序走。
为什么 styled-components 在 app/ 目录下直接 import 就炸
Next.js 14 的 App Router 默认启用服务端组件(Server Components),而 styled-components 的 createGlobalStyle、ThemeProvider、甚至普通 styled 组件,都依赖客户端 JS 执行后才挂载样式。服务端渲染时若没捕获样式, 里就空着,客户端 hydration 时发现 DOM 不匹配,React 就强制丢弃服务端 HTML、重新 client-render —— 表现为闪屏、动画中断、SEO 失效。
- 错误典型提示:
Warning: Prop `className` did not match. Server: "sc-bdVaJa" Client: "sc-gsDKAQ" - 根本卡点:服务端没生成
<style></style>标签,或生成了但没塞进 HTML 的 -
app/layout.tsx是服务端组件,默认不执行 JS,所以import { ThemeProvider } from 'styled-components'这行代码在服务端根本不会运行
如何让 styled-components 在 app/ 下真正支持 SSR
必须拆成两层:服务端负责提取样式,客户端负责接管交互。缺一不可。
- 在
app/layout.tsx顶部加"use client",否则ThemeProvider和GlobalStyle根本不执行 - 用
ServerStyleSheet+renderToString提取服务端样式(需自定义render函数)—— 但 App Router 不暴露renderToString,所以得退到pages/或改用@emotion/server配合CacheProvider - 更现实的路径:放弃
styled-components的 SSR 支持,改用@emotion/react+@emotion/server,它提供extractCritical和CacheProvider,能和 App Router 的generateStaticParams/dynamic="force-dynamic"协同工作 - 关键配置项:
cache必须跨请求复用(不能每次 new),且extractCritical返回的html和css要手动注入head的<style></style>标签中
为什么 styled-jsx 不报错,且不用配任何东西
因为它是 Next.js 原生绑定的方案,构建阶段就完成所有事,不依赖客户端 JS 执行。
立即学习“前端免费学习笔记(深入)”;
-
<style jsx></style>块在next build时被babel-plugin-styled-jsx静态解析,生成带哈希的类名和对应<style></style>标签,直接写入 HTML - 服务端吐出的 HTML 已含完整样式,客户端 hydration 时无需再计算、插入或比对,零 runtime 开销
- 伪类、媒体查询、CSS 变量全支持,且默认局部作用域,
:global(.btn)可破局,:global(body)也能写全局重置 - 唯一限制:无法在服务端组件里用 JavaScript 动态生成样式(比如
color: props.primary ? 'blue' : 'gray'),因为服务端组件不允许使用 props 传入样式逻辑
遇到 Global CSS must be in your custom _app.js 错误怎么办
这个错误只出现在 pages/ 路由下,和 CSS-in-JS 无关,但新手常混淆。它的意思是:你试图在非 _app.js 文件里 import '../styles.css',而 Next.js 禁止这种写法,防止样式加载顺序错乱。
- 解决方式只有两个:
import '../styles.css'必须挪到pages/_app.js;或者把文件重命名为styles.module.css,再按模块方式导入 - 注意:
app/目录下没有_app.js,所以这个错误不会出现 —— 但如果你混用pages/和app/,又在pages/index.js里 import 全局 CSS,就会触发 - 真实坑点:有些 UI 库(如 Ant Design)文档仍教你在组件里 import 全局 CSS,这在 Next.js 14 的
pages/下会直接报错,必须改用cssinjs方式或抽到_app.js
最易被忽略的点:App Router 下,styled-components 的 keyframes 和 css 辅助函数默认不参与 SSR 提取,哪怕你配好了 ServerStyleSheet,动画帧也可能首屏不播放。这时候要么切到 @emotion/react,要么把动画逻辑下沉到客户端组件并用 useEffect 触发,但会牺牲首屏体验。


















