服务端渲染中CSS未生效的核心原因是样式未被提取并内联到HTML的中;mini-css-extract-plugin不适用于SSR,而extract-css-chunks-webpack-plugin支持服务端获取样式字符串;Next.js默认支持styled-jsx,emotion需配合@emotion/server和自定义Document;Vue SSR须替换vue-style-loader为vue-server-renderer兼容方案,并确保版本匹配。

服务端渲染中 CSS 样式未生效的典型表现
页面首屏闪动(FOUC)、样式丢失、组件渲染后才突然“跳”出正确样式,基本都指向 css 在 SSR 流程中没被正确提取或注入。核心问题不是“有没有写 CSS”,而是“服务端是否把当前页面用到的样式提前收集并内联进 HTML 的 中”。React/Vue 等框架的服务端渲染默认不自动做这件事,需要显式配置。
使用 extract-css-chunks-webpack-plugin 或 mini-css-extract-plugin 的关键区别
两者都用于 Webpack 构建时分离 CSS,但在 SSR 场景下行为差异极大:
-
mini-css-extract-plugin会把 CSS 提取为独立文件(.css),服务端无法读取其内容,也就没法注入到 HTML 中;它只适合纯客户端渲染或 CSR fallback 场景 -
extract-css-chunks-webpack-plugin(已归入@teamsupercell/extract-css-chunks-webpack-plugin)支持在服务端运行时通过getSheetList()或类似 API 获取当前 chunk 对应的样式字符串,是 SSR 友好的选择 - 若用 Vite + SSR,需改用
vite-plugin-css-injected-by-js或手动在renderToString后调用ssrLoadModule读取__vite_ssr_import_meta__.hot中的样式模块
Next.js 中 styled-jsx 与 emotion 的服务端样式提取方式
Next.js 默认支持 styled-jsx 的服务端样式提取,无需额外配置;但使用 emotion 时必须启用 @emotion/server 并配合自定义 Document 组件:
import { renderStylesToString } from '@emotion/server';
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
const styles = renderStylesToString(ctx.renderPage());
return { ...initialProps, styles };
}
render() {
return (
);
}
}
漏掉 renderStylesToString 调用,或未在 中插入,就会导致 emotion 样式仅在客户端计算并注入,破坏 SSR 一致性。
立即学习“前端免费学习笔记(深入)”;
Vue SSR 中 vue-style-loader 必须替换为 vue-server-renderer 兼容方案
开发时用的 vue-style-loader 依赖浏览器 DOM API,在 Node.js 环境直接报错:ReferenceError: document is not defined。解决方法是 Webpack 配置中对服务端构建单独 alias:
module.exports = {
resolve: {
alias: {
'vue-style-loader': 'vue-server-renderer/basic'
}
}
}
同时确保 vue-server-renderer 版本与 Vue 版本严格匹配(如 Vue 2.7 → vue-server-renderer@2.7.x),否则会出现样式提取为空或重复注入的问题。
最常被忽略的是:服务端提取的样式必须和客户端 hydrate 时的样式顺序、作用域完全一致,否则 React/Vue 会因 checksum 不匹配而丢弃整个 DOM 并重新挂载——这会让 SSR 失去意义。










