一文讲清 CSR、SSR、SSG:前端页面到底在哪里渲染?

前言

前端页面最终都会变成浏览器里的 HTML、CSS 和 JavaScript。

但问题是:

这份 HTML 是在哪里生成的?

是在浏览器里由 JavaScript 临时生成?
是在服务器收到请求时实时生成?
还是在项目构建时提前生成好?

这三个答案,分别对应了前端里最常见的三种渲染模式:

  • CSR:Client-Side Rendering,客户端渲染
  • SSR:Server-Side Rendering,服务端渲染
  • SSG:Static Site Generation,静态站点生成

很多性能、SEO、白屏时间、部署复杂度、缓存策略的问题,本质上都和这三个模式有关。


一、先把“渲染”这件事说清楚

在前端语境里,“渲染”通常不是指浏览器把像素画到屏幕上,而是指:

把数据和组件代码,变成浏览器可以展示的 HTML 结构。

比如我们有一段商品数据:

1
2
3
4
const product = {
name: '机械键盘',
price: 399,
};

以及一个组件:

1
2
3
4
5
6
7
8
9
function ProductCard({ product }) {
return (
<div className="product-card">
<h2>{product.name}</h2>
<p>¥{product.price}</p>
<button>加入购物车</button>
</div>
);
}

渲染之后,最终会得到类似这样的 HTML:

1
2
3
4
5
<div class="product-card">
<h2>机械键盘</h2>
<p>¥399</p>
<button>加入购物车</button>
</div>

CSR、SSR、SSG 的区别,不是最终有没有 HTML,而是:

这段 HTML 是什么时候、在哪里生成的。


二、CSR:客户端渲染

CSR 的全称是 Client-Side Rendering,也就是客户端渲染。

它的核心思路是:

服务器先返回一个几乎空的 HTML,浏览器下载 JavaScript 后,再由 JS 在客户端生成页面内容。

CSR 的典型流程

一个典型的 CSR 页面,服务器返回的 HTML 可能长这样:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>商城</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>

注意这里的 <div id="root"></div> 是空的。

浏览器拿到这个 HTML 后,页面本身还没有真正内容。接下来它需要:

  1. 下载 JavaScript bundle
  2. 执行 JavaScript
  3. 请求接口数据
  4. 根据数据生成 DOM
  5. 把内容渲染到页面上

流程可以简化成:

1
2
3
4
5
6
7
浏览器请求页面
-> 服务器返回空壳 HTML
-> 浏览器下载 JS
-> JS 执行
-> 请求接口数据
-> 客户端生成页面
-> 用户看到完整内容

React 里的写法通常是:

1
2
3
4
import { createRoot } from 'react-dom/client';
import App from './App';

createRoot(document.getElementById('root')).render(<App />);

这表示浏览器拿到 JS 后,在 #root 这个节点里把整个应用渲染出来。

CSR 的优点

CSR 最大的优点是 前后端职责清晰。

服务器主要负责:

  • 提供一个 HTML 入口
  • 提供静态资源
  • 提供 API 接口

浏览器负责:

  • 路由切换
  • 页面渲染
  • 状态管理
  • 交互逻辑

这非常适合后台管理系统、SaaS 控制台、复杂 Web App。因为这些系统通常:

  • 登录后才能访问
  • SEO 不重要
  • 页面交互复杂
  • 用户会在站内停留较久
  • 路由切换频繁

CSR 一旦应用加载完成,后续页面切换通常很顺滑,因为很多逻辑都在客户端完成。

CSR 的缺点

CSR 最大的问题是 首屏慢。

因为服务器一开始只返回空壳 HTML,用户真正看到内容之前,必须等 JS 下载、解析、执行完成。如果 bundle 很大,或者网络很慢,就容易出现白屏。

第二个问题是 SEO 不友好。

搜索引擎爬虫拿到的初始 HTML 可能只有:

1
<div id="root"></div>

虽然现代搜索引擎已经可以执行一部分 JavaScript,但这仍然比直接给完整 HTML 更不稳定,尤其是对内容型网站、电商详情页、博客文章页来说。

第三个问题是 低端设备体验差。

CSR 把大量工作放到了浏览器端。如果用户使用的是低端手机,JavaScript 的解析和执行会明显拖慢页面可用时间。

CSR 适合什么场景

CSR 适合:

  • 后台管理系统
  • 数据看板
  • 在线编辑器
  • IM、邮箱、协作工具
  • 登录后使用的复杂应用
  • SEO 不重要、交互很重的产品

一句话总结:

CSR 适合“应用型页面”,不太适合强依赖首屏速度和 SEO 的公开内容页。


三、SSR:服务端渲染

SSR 的全称是 Server-Side Rendering,也就是服务端渲染。

它的核心思路是:

服务器收到请求后,先在服务端把页面渲染成完整 HTML,再返回给浏览器。

也就是说,浏览器第一次拿到的 HTML 里就已经有页面内容。

SSR 的典型流程

SSR 的流程可以简化成:

1
2
3
4
5
6
7
8
9
浏览器请求页面
-> 服务器获取页面所需数据
-> 服务器执行组件渲染逻辑
-> 生成完整 HTML
-> 返回给浏览器
-> 浏览器立即展示内容
-> 下载 JS
-> 水合 Hydration
-> 页面变得可交互

服务端生成的 HTML 可能是:

1
2
3
4
5
6
7
<div id="root">
<div class="product-card">
<h2>机械键盘</h2>
<p>¥399</p>
<button>加入购物车</button>
</div>
</div>

用户拿到页面后,不需要等 JavaScript 执行完,通常就能先看到内容。

React 服务端渲染大概是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { renderToString } from 'react-dom/server';

const html = renderToString(<App />);

res.send(`
<!DOCTYPE html>
<html>
<body>
<div id="root">${html}</div>
<script src="/client.js"></script>
</body>
</html>
`);

SSR 为什么还需要水合

SSR 返回的 HTML 虽然能展示内容,但它本身是“静态”的。

HTML 里没有组件状态,没有事件处理函数,也没有 React/Vue 运行时的组件关系。

所以浏览器下载 JavaScript 后,还需要执行一次客户端接管过程:

1
2
3
import { hydrateRoot } from 'react-dom/client';

hydrateRoot(document.getElementById('root'), <App />);

这一步叫 Hydration(水合)。

它的作用是:

  • 复用服务端已经生成的 DOM
  • 绑定事件监听器
  • 恢复组件状态
  • 让页面从“能看”变成“能操作”

所以 SSR 页面通常有一个很重要的时间窗口:

1
看到内容 -> JS 下载执行 -> 水合完成 -> 可以交互

也就是说,SSR 优化的是“更早看到内容”,但不一定代表“更早可以交互”。

SSR 的优点

SSR 最大的优点是 首屏内容出现更快。

浏览器拿到的第一份 HTML 就已经包含真实内容,所以用户可以更快看到页面。这对内容页、电商详情页、营销页非常重要。

第二个优点是 SEO 更友好。

搜索引擎爬虫拿到的是完整 HTML,更容易抓取标题、正文、商品信息、结构化数据等内容。

第三个优点是 弱网下体验更好。

即使 JavaScript 下载慢,用户也可能先看到页面主要内容,而不是一直面对空白页。

SSR 的缺点

SSR 的第一个缺点是 服务器压力更大。

CSR 模式下,服务器大多只需要返回静态文件和 API 数据。SSR 模式下,每次请求页面时,服务器都要执行渲染逻辑,生成 HTML。

访问量大时,SSR 会带来更高的 CPU 和内存压力。

第二个缺点是 架构复杂度更高。

因为同一套组件代码可能既要在浏览器跑,也要在 Node.js 服务端跑。开发时要注意:

  • 服务端没有 window
  • 服务端没有 document
  • 服务端不能直接访问浏览器存储
  • 数据请求要兼顾服务端和客户端
  • 两端渲染结果必须一致

第三个缺点是 可能出现水合不匹配。

如果服务端渲染出的 HTML 和客户端第一次渲染出的结果不一致,就会出现 Hydration Mismatch。

常见原因包括:

  • 直接在渲染阶段使用 Date.now()
  • 直接在渲染阶段使用 Math.random()
  • 根据 window.innerWidth 决定首屏结构
  • 服务端和客户端拿到的数据不一致

这些都会导致服务端 HTML 和客户端虚拟 DOM 对不上。

SSR 适合什么场景

SSR 适合:

  • 新闻资讯页
  • 博客文章页
  • 电商商品详情页
  • 需要 SEO 的官网
  • 首屏速度要求高的公开页面
  • 需要根据请求实时生成内容的页面

一句话总结:

SSR 适合“内容要尽快出现,而且内容需要按请求实时变化”的页面。


四、SSG:静态站点生成

SSG 的全称是 Static Site Generation,也就是静态站点生成。

它的核心思路是:

页面不是在用户请求时生成,而是在项目构建时提前生成成静态 HTML。

也就是说,构建阶段就把页面都算好了。

SSG 的典型流程

SSG 的构建流程是:

1
2
3
4
5
6
执行构建命令
-> 读取页面代码
-> 获取构建时需要的数据
-> 生成静态 HTML
-> 生成静态 CSS / JS
-> 部署到 CDN 或静态服务器

用户访问时的流程是:

1
2
3
4
5
浏览器请求页面
-> CDN 直接返回已经生成好的 HTML
-> 浏览器展示内容
-> 下载 JS
-> 页面变得可交互

比如一个博客站点,在构建时可以把每篇文章都生成成单独的 HTML:

1
2
3
/posts/csr-ssr-ssg.html
/posts/react-hydration.html
/posts/frontend-engineering.html

用户访问 /posts/csr-ssr-ssg.html 时,服务器不需要实时渲染,只要返回已经存在的静态文件。

SSG 的优点

SSG 最大的优点是 快。

因为页面已经提前生成,用户访问时不需要服务器实时计算。静态 HTML 可以直接放在 CDN 上,就近返回给用户。

第二个优点是 稳定。

静态文件不依赖运行时服务。只要 CDN 或静态服务器正常,页面就能访问。没有数据库临时抖动、服务端渲染超时、运行时崩溃等问题。

第三个优点是 成本低。

静态站点不需要强大的服务器来实时渲染页面。很多博客、文档站、官网可以直接托管在静态站点平台上。

第四个优点是 SEO 友好。

因为 SSG 返回的也是完整 HTML,搜索引擎可以直接抓取页面内容。

SSG 的缺点

SSG 最大的问题是 内容更新不够实时。

如果页面是在构建时生成的,那么数据变化之后,页面不会自动更新,除非重新构建。

比如商品价格变了,如果商品详情页是纯 SSG,那么旧价格可能会一直留在静态 HTML 里,直到下一次构建。

第二个问题是 页面数量太多时构建慢。

如果一个站点有几十篇博客,SSG 很舒服。
但如果有几百万个商品详情页,全量构建就会非常慢。

第三个问题是 不适合高度个性化页面。

比如“我的订单”“我的消息”“我的推荐列表”,每个用户看到的都不一样。这类页面不适合提前生成成统一的静态 HTML。

SSG 适合什么场景

SSG 适合:

  • 博客
  • 文档站
  • 产品官网
  • 营销页
  • 作品集
  • 更新频率不高的内容页
  • 可以接受构建后发布的页面

一句话总结:

SSG 适合“内容相对固定、希望访问极快、希望部署简单”的页面。


五、CSR、SSR、SSG 的核心区别

三者最核心的区别是:

HTML 生成的时机不同。

渲染模式 HTML 生成时机 HTML 生成位置 首屏内容 SEO 服务器压力 内容实时性
CSR 浏览器运行时 客户端 慢,依赖 JS 较弱 低 强
SSR 每次请求时 服务端 快 好 高 强
SSG 构建时 构建机器 很快 好 很低 弱

再换一种更直观的说法:

1
2
3
CSR:用户来了,浏览器现场画页面
SSR:用户来了,服务器现场画页面
SSG:用户来之前,页面已经提前画好了

六、从用户访问过程看区别

CSR 的访问过程

1
2
3
4
5
6
7
8
请求 HTML
-> 拿到空壳
-> 下载 JS
-> 执行 JS
-> 请求数据
-> 生成页面
-> 看到内容
-> 可以交互

CSR 的特点是:

  • “看到内容”比较晚
  • “看到内容”和“可以交互”通常比较接近
  • 后续页面切换体验好

SSR 的访问过程

1
2
3
4
5
6
7
请求 HTML
-> 服务器请求数据
-> 服务器生成 HTML
-> 浏览器看到内容
-> 下载 JS
-> 水合
-> 可以交互

SSR 的特点是:

  • “看到内容”早
  • “可以交互”可能晚于“看到内容”
  • 每次页面请求都需要服务端参与渲染

SSG 的访问过程

1
2
3
4
5
6
7
构建阶段提前生成 HTML

用户请求 HTML
-> CDN 返回静态 HTML
-> 浏览器看到内容
-> 下载 JS
-> 可以交互

SSG 的特点是:

  • “看到内容”非常快
  • 运行时服务器压力很小
  • 内容更新依赖重新构建或增量更新

七、从性能指标看区别

前端性能里经常会提到这些指标:

  • FCP:First Contentful Paint,首次内容绘制
  • LCP:Largest Contentful Paint,最大内容绘制
  • TTI:Time to Interactive,可交互时间
  • TBT:Total Blocking Time,总阻塞时间

不同渲染模式对这些指标的影响不一样。

CSR 对性能指标的影响

CSR 通常会让 FCP 和 LCP 变晚。

因为页面内容依赖 JavaScript 生成。如果 JS 包很大,用户就要等更久才能看到主要内容。

但 CSR 应用加载完成后,站内切换通常很快,因为后续路由可以在客户端完成。

SSR 对性能指标的影响

SSR 通常可以改善 FCP 和 LCP。

因为浏览器更早拿到真实 HTML,能更早绘制内容。

但 SSR 不一定改善 TTI。页面虽然能看了,但还要等待 JavaScript 下载和水合完成。页面越复杂,水合成本越高。

所以 SSR 的典型体验可能是:

内容出现很快,但短时间内点按钮没有反应。

SSG 对性能指标的影响

SSG 通常对 FCP 和 LCP 很友好。

因为静态 HTML 可以通过 CDN 快速返回,浏览器能很快开始绘制。

如果页面交互不复杂,SSG 的整体性能通常很好。但如果 SSG 页面仍然加载了很大的客户端 JS,也同样会影响 TTI。


八、从 SEO 看区别

SEO 最关心的是:

爬虫第一次拿到的 HTML 里有没有真实内容。

CSR 的 SEO

CSR 对 SEO 相对不友好。

初始 HTML 内容少,正文、标题、商品信息可能都要等 JavaScript 执行后才出现。

对于搜索引擎来说,这增加了抓取和索引的不确定性。

SSR 的 SEO

SSR 对 SEO 友好。

因为爬虫请求页面时,服务端直接返回完整 HTML。

SSG 的 SEO

SSG 对 SEO 也友好。

因为页面在构建时已经生成完整 HTML,爬虫访问时可以直接读取内容。

如果一个页面特别依赖 SEO,通常优先考虑 SSR 或 SSG,而不是纯 CSR。


九、从数据实时性看区别

渲染模式和数据实时性关系很大。

CSR 的数据实时性

CSR 通常实时性很好。

页面打开后可以直接请求最新 API 数据。只要接口返回的是最新数据,页面就能展示最新内容。

SSR 的数据实时性

SSR 实时性也很好。

每次请求页面时,服务器都可以重新获取最新数据,再生成 HTML。

比如用户访问商品详情页时,服务端可以实时读取最新价格和库存。

SSG 的数据实时性

SSG 的实时性较弱。

因为页面是在构建时生成的。构建之后,如果数据变了,静态 HTML 不会自动变化。

所以 SSG 更适合内容相对稳定的页面。


十、ISR:介于 SSR 和 SSG 之间

实际业务里经常会遇到一种尴尬情况:

页面希望像 SSG 一样快,但内容又不能永远不更新。

这时就出现了 ISR。

ISR 的全称是 Incremental Static Regeneration,增量静态再生成。

它的核心思路是:

先用静态页面承接访问,再按一定规则在后台重新生成页面。

比如一个商品详情页设置 60 秒重新生成一次:

1
2
3
4
5
第一次构建生成静态 HTML
-> 用户访问,直接返回静态 HTML
-> 超过 60 秒后,下一次访问仍先返回旧页面
-> 后台重新生成新页面
-> 后续用户拿到新页面

ISR 试图在三件事之间找平衡:

  • 静态页面的访问速度
  • 动态内容的更新能力
  • 服务器渲染的成本

它很适合:

  • 商品详情页
  • 内容详情页
  • 大量页面但不需要秒级实时更新的站点
  • 希望使用 CDN 缓存,又希望内容能自动刷新的页面

不过 ISR 不是所有框架都有的通用能力,它更多是 Next.js 等框架提供的一种具体工程方案。


十一、怎么选择

选择渲染模式时,可以先问几个问题。

1. 这个页面需要 SEO 吗?

如果需要 SEO,优先考虑 SSR 或 SSG。

比如:

  • 文章页
  • 商品详情页
  • 官网首页
  • 营销落地页

如果不需要 SEO,比如登录后的管理后台,CSR 通常就够了。

2. 这个页面内容更新频繁吗?

如果内容每次访问都要最新,适合 SSR 或 CSR。

比如:

  • 用户订单
  • 实时库存
  • 个性化推荐
  • 登录用户首页

如果内容一天更新几次,或者发布后才更新,SSG 或 ISR 更合适。

3. 这个页面是不是每个用户都不一样?

如果每个用户看到的内容都不同,不适合纯 SSG。

比如:

  • 我的订单
  • 我的账户
  • 我的消息
  • 个性化工作台

这类页面通常使用 CSR,或者 SSR 加用户态数据。

4. 首屏速度是不是特别重要?

如果首屏速度很重要,优先考虑 SSR、SSG 或 ISR。

CSR 也可以通过代码分割、骨架屏、预加载等方式优化,但它的天然劣势是首屏依赖客户端 JS。

5. 能不能接受更复杂的服务端架构?

SSR 能带来更好的首屏和 SEO,但也会增加服务器运行时复杂度。

如果团队更希望部署简单、成本低、稳定性高,SSG 是很好的选择。


十二、常见页面应该怎么选

页面类型 推荐模式 原因
博客文章 SSG 内容稳定,SEO 重要,访问速度要求高
文档站 SSG 页面多但更新可控,适合静态部署
官网首页 SSG / SSR SEO 重要,内容不频繁变化时用 SSG
新闻详情页 SSR / ISR SEO 重要,内容更新较频繁
商品详情页 SSR / ISR SEO 重要,价格库存可能变化
后台管理系统 CSR SEO 不重要,交互复杂
用户订单页 CSR / SSR 用户态强,数据实时且个性化
数据看板 CSR 交互复杂,依赖实时接口
营销活动页 SSG / SSR 首屏和 SEO 重要

十三、不要把渲染模式理解成只能三选一

真实项目里,CSR、SSR、SSG 经常是混合使用的。

比如一个电商网站可以这样设计:

  • 首页:SSG 或 ISR
  • 商品列表页:SSR
  • 商品详情页:ISR
  • 搜索页:SSR 或 CSR
  • 购物车:CSR
  • 订单页:CSR
  • 管理后台:CSR

一个技术站点也可以这样设计:

  • 文档页:SSG
  • 博客页:SSG
  • 搜索功能:CSR
  • 评论区:CSR
  • 用户中心:CSR

所以更准确的思路不是“整个项目用什么渲染模式”,而是:

每一类页面应该选择什么渲染模式。


十四、三者的关系总结

可以用一句话概括:

CSR 把渲染压力交给浏览器,SSR 把渲染压力交给服务器,SSG 把渲染工作提前到构建阶段。

再从核心取舍来看:

  • CSR:开发和部署简单,适合强交互应用,但首屏和 SEO 较弱
  • SSR:首屏和 SEO 好,数据实时,但服务端压力和复杂度更高
  • SSG:访问最快、最稳定、成本低,但内容实时性较弱
  • ISR:在 SSG 的基础上补充更新能力,适合大量不需要秒级实时的页面

最终选择时,不要只问“哪个模式最好”,而要问:

这个页面更需要首屏速度、SEO、实时性、交互体验,还是部署简单?

渲染模式没有绝对优劣,只有场景匹配。