定義
ページ内で最も大きなコンテンツ(多くはヒーロー見出しや大きな画像)が画面に描画される時刻を LCP(Largest Contentful Paint)と呼ぶ。この LCP が遅いのに 画像のバイト数が小さく、メインスレッドも空いている(TBT≈0) なら、ボトルネックは「ダウンロード」ではなく、その LCP 要素がクライアントコンポーネント境界の中にあり、JavaScript の hydration が終わって初めて描画されること だ。Lighthouse はこれを LCP breakdown の「element render delay」(要素が準備できてから実際に描画されるまでの遅延)として示す。
用語をほどくと、hydration はサーバーが生成した静的 HTML に React が後からイベントを付けて動くようにする過程であり、TBT(Total Blocking Time) はメインスレッドが長いタスクに塞がれて入力に反応できなかった総時間だ。
なぜ必要か
症状: LCP が 5 秒台と遅い。直感的に「ヒーロー画像を小さくしよう」が浮かぶ。ところが画像をいくら圧縮してもスコアが上がらない。LCP 要素が "use client" コンポーネント + アニメーションライブラリの中にあると、サーバー HTML は空か未完成で、ブラウザがそのチャンクを受け取って hydration を終えてから初めて最終ピクセルが出る。つまり ペイントが JavaScript の実行に人質に取られている。このとき攻略対象はアセットではなく「その境界からクライアント JS を外すこと」だ。診断を誤ると何日も画像最適化に浪費してもスコアはそのままになる。
動作原理
Lighthouse は LCP を 4 つの区間に分ける。
| 区間 | 意味 | これが大きいと |
|---|---|---|
| TTFB | サーバーの最初のバイトまで | サーバー/ネットワーク |
| load delay | LCP リソースの発見が遅い | 遅い preload/発見 |
| load time | LCP リソースのダウンロード時間 | 大きな画像 |
| render delay | リソースは準備できたが描画までの遅延 | hydration/レンダー阻害 |
画像が小さく TTFB も正常なのに render delay が大きいなら、LCP 要素がクライアント境界の中にあり、そのチャンクのダウンロード+実行がペイントの前を塞いでいるというサインだ。サーバーコンポーネントでレンダーすれば最終マークアップが最初の HTML にすでに入っており、hydration を待つ必要がない。
実務での適用
-
breakdown を確認 — Lighthouse の LCP insight で render delay の値を見る。大きければ hydration を疑う。
-
LCP サーフェスをサーバー化 — ヒーロー・上部のストーリーセクションをサーバーコンポーネントに変え、動きが必要ならアニメーションライブラリの代わりに CSS(スクロール駆動アニメーションなど)で置き換える。
-
重いプロバイダを隔離 — auth/query/motion/サービスワーカーなど重いコンテキストプロバイダを最上位ではなくアプリサーフェス専用のレイアウトに下ろし、静的ランディングチャンクから完全に外す。
-
状態がどうしても必要なら最小化 — トリガー一度きりの登場効果は IntersectionObserver 一片だけをクライアントに置く。
トレードオフ
- サーバー化 + CSS への切り替え は diff が大きいが、ランディングチャンクからライブラリを丸ごと除去するので効果が確実だ。逆にライブラリの
LazyMotionのような部分最適化は diff は小さくても、そのライブラリは依然チャンクに残る。 - 測定の罠: Lighthouse のシミュレーション(Lantern、CPU を 4 倍遅く仮定)は下限を作り、実際の観測 LCP と大きく異なりうる。ある地点からはコードではなくシミュの下限なので、それ以上は縮まない — このときは止めるのが正しい。
使ってはいけない場合
- LCP 要素が本当に大きな画像で load time が支配的なら、ここの処方(サーバー化)ではなく画像最適化が答えだ。まず breakdown でどの区間かを確定する。
- 強い操作性が上部に必ず必要なアプリ画面(ダッシュボードなど)で無理にクライアント JS を外すと機能が壊れる — ランディング/マーケティング表面に集中する。
よくあるミス
- LCP が遅い = 画像の問題と決めつけて render delay を見ない。
- 大きな元画像を小さく表示するブランドマークをそのまま残す — フレームワークが初期 HTML の
<img>を自動 preload し、クリティカルパスに大きなバイトを載せる(専用の小型アセットが必要)。 - シミュの下限に到達したのに最適化に時間を使い続ける(過投資)。
関連概念
- largest-contentful-paint — LCP 指標そのものと一般的な最適化
- critical-rendering-path — HTML→レンダーの経路と阻害要因
- scroll-driven-narrative-layout — モーションを CSS で置き換えるサーバー親和なレイアウト
- lighthouse-measurement-accuracy — シミュの下限と observed の差
- readonly-viewer-bundle-splitting — 表面ごとに重い依存を除去