Next.js SSR中CSS样式在服务端渲染后空白,怎么解决?
我在用Next.js做SSR的时候遇到个怪问题,布局组件里的CSS样式在服务端渲染后页面直接显示空白了,但控制台没报错,刷新后又能正常显示。折腾了半天发现是CSS加载的问题。
代码结构大概是这样的:在_pages/layout.tsx里这样导入CSS文件:import '@/styles/global.css',然后服务端渲染时页面元素虽然结构对,但所有样式都失效了,导致文字和容器都挤在一起。
我尝试过把CSS抽到组件内部用动态导入:
import dynamic from 'next/dynamic'
const Style = dynamic(() => import('../styles/detail.css'), { ssr: true })
但这样反而报找不到文件路径的错误。后来改成用标签引入也没用。
附上出问题的CSS片段:
.content-container {
@apply px-4 py-6 max-w-4xl mx-auto;
}
.product-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
这种情况下应该怎么调整SSR的CSS配置?是路径问题还是需要配置样式提取?
就这样。
首先检查一下你的入口文件,也就是_app.tsx里有没有正确引入全局样式。Next.js的SSR要求全局CSS必须在页面组件之外引入,最好是放在_app.tsx里。如果你直接在_layout.tsx这种组件里import '@/styles/global.css',那CSS是不会被SSR处理的。
解决方法很简单:在你的_pages/_app.tsx里这样引入全局样式:
import '../styles/global.css'
然后如果你在_layout.tsx里还写了import '@/styles/global.css',一定要删掉这一行。因为Next.js的机制是要求全局样式必须在_app.tsx里引入,否则服务端渲染的时候样式不会被正确注入到HTML里,这就导致你看到的空白页面。
至于你提到的动态导入CSS的方式,那其实是给组件级别的CSS用的,比如用CSS-in-JS或者局部样式。如果你用的是全局CSS,那必须走_app.tsx引入这条路。还有你提到的用标签引入CSS其实也不太对,因为Next.js默认是不支持服务端加载外部CSS文件的,除非你自己写自定义的Document组件来处理。
最后检查一下你的next.config.js有没有CSS配置问题,正常情况默认是支持全局CSS的。如果你动过webpack配置或者用了CSS模块化之类的高级功能,那可能还需要额外调整。
你这个问题应该按上面的方法就能解决,CSS的话有时候真的挺玄学,但官方推荐的全局样式写法就是_app.tsx里引入,其他的局部样式可以按需引入。