レンダリング戦略のフェーズ全体図 — いつ何が見えるか

CSR・SSR・SSG・SPA を時間軸のフェーズで捉え直した初学者向けの全体図。各戦略の違いは、結局「どのフェーズで HTML を作り、ユーザーがいつ・何を見るか」の違いでしかない。より厳密な定義・比較・歴史は rendering-strategies へ。

まず地図 — 4 つの言葉は 2 つの軸に分かれる

CSR / SPA / SSR / SSG と 4 つ並ぶと同格に見えるが、実は答えている質問が違う。

質問答えの選択肢
初回アクセス — 最初の HTML をいつ・どこで作る?CSR(ブラウザがその場で作る)/ SSR(リクエストのたびサーバーで作る)/ SSG(デプロイ前に作り置き)
2 ページ目以降 — ページ移動をどう動かす?SPA(リロードせず差し替え)/ MPA(毎回リロード)

2 つの軸は組み合わせ自由。Next.js は「SSR/SSG + SPA」、Rails は「SSR + MPA」、Vite + React の素の構成は「CSR + SPA」。CSR と SPA は「画面づくりをブラウザに任せる」という同じ思想の初回編と遷移編なので、昔からセットで登場する。ただし軸としては独立していて、「初回だけサーバーに任せて、遷移はブラウザ」(SSR + SPA)という組み替えができる — これが現代フレームワークの肝。

共通のものさし — 6 つのフェーズ

どの戦略も、ユーザーがページを開いてから操作できるまでに通る道は同じ。違うのは各フェーズの長さと、そこで何が見えているか。

フェーズ何が起きるか対応する指標
⓪ ビルドデプロイ前にコードや HTML を準備する—
① リクエストブラウザがサーバーに「ページください」TTFB(最初の 1 バイトまで)
② HTML 到着返ってきた HTML をブラウザが表示するFCP(最初に何か見えるまで)
③ JS ロード・実行JS をダウンロードして動かす—
④ データ取得API から中身のデータをもらう—
⑤ 操作可能クリックや入力に反応するようになるTTI(操作できるまで)

ユーザーの見え方は 3 段階しかない。以降の図では、この 3 段階をノードの色で塗り分ける。

graph LR
    L1["白い画面<br/>(まだ何も見えない)"] --> L2["見えるが押せない<br/>(表示済み・反応しない)"] --> L3["見えて押せる<br/>(操作可能)"]
    classDef blank fill:#1E293B,stroke:#64748B,stroke-dasharray: 5 4,color:#94A3B8
    classDef visible fill:#422006,stroke:#F59E0B,color:#FDE68A
    classDef ready fill:#14532D,stroke:#4ADE80,color:#BBF7D0
    class L1 blank
    class L2 visible
    class L3 ready

CSR — 「見える」が全部後ろに寄る

graph LR
    A["① リクエスト<br/>白い画面"] --> B["② 空の HTML 到着<br/>まだ白い(中身は空 div)"]
    B --> C["③ JS ロード・実行<br/>まだ白い"]
    C --> D["④ API からデータ取得<br/>白い画面 or スピナー"]
    D --> E["⑤ 描画 + 操作可能<br/>FCP と TTI が最後に一気に来る"]
    classDef blank fill:#1E293B,stroke:#64748B,stroke-dasharray: 5 4,color:#94A3B8
    classDef ready fill:#14532D,stroke:#4ADE80,color:#BBF7D0
    class A,B,C,D blank
    class E ready

SPA — CSR の続き: 「2 ページ目以降」の図

CSR の続きの話。CSR が「初回の画面をブラウザで描く」なら、SPA は「2 ページ目以降もブラウザで描き続ける」— 同じ思想の遷移編で、だから CSR とセットで使われてきた。ただし担当する時間帯が違うので、初回だけ SSR/SSG に差し替えることもできる(冒頭の「まず地図」の 2 軸目)。

graph LR
    A["① リンクをクリック<br/>JS が横取りして preventDefault"] --> B["② URL だけ書き換え<br/>pushState(リロードしない)"]
    B --> C["③ 必要なデータだけ fetch<br/>画面は生きたまま"]
    C --> D["④ DOM を差し替え<br/>状態・スクロール・接続を保ったまま次のページ"]
    classDef ready fill:#14532D,stroke:#4ADE80,color:#BBF7D0
    class C,D ready

ここまでが古典 SPA(CSR + SPA)の全体像 — 初回は重いが、入ってしまえば快適。この「初回の重さ」を解決するのが、次の SSR と SSG。

SSR — すぐ見えるが、少しの間押せない

graph LR
    A["①+④ リクエスト&データ取得<br/>白い画面(サーバーが調理中)"] --> B["② 完成 HTML 到着<br/>FCP! 見えた、でも押せない"]
    B --> C["③ JS ロード + hydration<br/>押せない時間の正体"]
    C --> D["⑤ 操作可能<br/>TTI"]
    classDef blank fill:#1E293B,stroke:#64748B,stroke-dasharray: 5 4,color:#94A3B8
    classDef visible fill:#422006,stroke:#F59E0B,color:#FDE68A
    classDef ready fill:#14532D,stroke:#4ADE80,color:#BBF7D0
    class A blank
    class B,C visible
    class D ready

SSG — ユーザーが来る前に、もう出来ている

graph LR
    Z["⓪+④ ビルドで全ページ生成&データ取得<br/>ユーザーが来る前に完成済み"] -.-> A
    A["① リクエスト<br/>一瞬(CDN がファイルを返すだけ)"] --> B["② 完成 HTML 到着<br/>最速で見える、まだ押せない"]
    B --> C["③ JS + hydration(あれば)<br/>⑤ 操作可能"]
    classDef blank fill:#1E293B,stroke:#64748B,stroke-dasharray: 5 4,color:#94A3B8
    classDef visible fill:#422006,stroke:#F59E0B,color:#FDE68A
    classDef ready fill:#14532D,stroke:#4ADE80,color:#BBF7D0
    class A blank
    class B visible
    class C ready

横並び — 同じ瞬間に、何が見えているか

フェーズCSRSSRSSG
① リクエスト直後白い画面(一瞬で返る)白い画面(サーバー調理中)白い画面(一瞬で返る)
② HTML 到着まだ白い(中身が空)完成画面(押せない)完成画面(押せない)
③ JS 実行後まだデータ待ち押せる押せる
④ データ取得後やっと見えて押せる—(サーバーで済み)—(ビルドで済み)

同じ「①→⑤」を通るのに、「見える」「押せる」が現れるタイミングだけがずれていることが分かれば、この 3 つは理解できたと言っていい。

結局どれを選ぶ? — 2 つの質問で決まる

graph TD
    Q1{"Google 検索や SNS から<br/>初見の人が来る?"} -->|"来ない(ログインして使うツール)"| CSR["CSR<br/>管理画面・社内ツール"]
    Q1 -->|"来る"| Q2{"中身は見る人や<br/>タイミングで変わる?"}
    Q2 -->|"誰が見ても同じ"| SSG["SSG<br/>ブログ・LP・ドキュメント"]
    Q2 -->|"変わる"| SSR["SSR<br/>EC・ニュース・SNS"]
作るもの質問への答え選択
社内の勤怠管理ツール検索から人は来ないCSR
会社ブログ・製品 LP検索から来る・誰が見ても同じSSG
ドキュメントサイト検索から来る・誰が見ても同じSSG
EC の商品ページ検索から来る・価格や在庫が変わるSSR
SNS のタイムライン人ごとに中身が違うSSR

実際のフレームワーク(Next.js 等)はページごとに戦略を混ぜられるので、「サイト全体でどれか 1 つ」と思わなくていい。トップは SSG、商品ページは SSR、マイページは CSR、が普通にできる。

覚え方 — レンダリング費用を「誰が・いつ」払うか

HTML を作る計算は必ずどこかで誰かが払う。戦略の違いは支払いの場所とタイミングの違い。

戦略払う人払うタイミング食堂に例えると
SSGビルドサーバーデプロイ前に 1 回だけ作り置きのお弁当 — 渡すのは一瞬。全員同じ中身
SSR運営のサーバーリクエストのたび注文を受けてから作る定食 — 好みに合わせられるが、待ち時間は厨房次第
CSRユーザーの端末訪問のたび食材とレシピを渡して自分で調理 — 店は楽。速さは客のコンロ次第
SPA—(別軸)遷移のたび(差分だけ)入店後の追加注文 — 店を出入りし直さず、席(状態)を保ったまま

押さえどころ(カード化候補)

関連

Graph