TL;DR
- フロント性能改善は 「何から潰すか」の順序で ROI が桁違いに変わる。並行で全部やると優先度が崩壊する
- 公式(web.dev / Core Web Vitals)が示すユーザー体感の3指標は LCP・INP・CLS。改善順序もこの並びが基本
- まずは RUM(実ユーザー計測)で現実を測る のが先。Lighthouse スコアは「Lab値」で実体感とズレる
- 2024-03 から INP が CWV 入りした。FID 時代の知識でアップデートしていないチームは要注意
- 末尾に 改善優先度チェックリスト(12項目) を置く。チームに展開しやすい形で持ち帰ってほしい
なぜ「順序」を間違えるとフロント性能改善は失敗するのか
こんにちは、みねです。
「Lighthouse スコアを上げてくれ」とプロダクトマネージャから降ってきて、バンドル削減 → 画像最適化 → CDN チューニングを順番にやったのに、ユーザーの体感速度はほとんど変わらない。CV も離脱率も動かない。こんな経験、フロントエンドの現場では珍しくない。
原因はシンプルで、改善の順序がビジネス指標と噛み合っていない からだ。フロント性能の打ち手は数十種類あるが、ユーザー体感に効く打ち手と、Lighthouse スコアにしか効かない打ち手は別物だ。順序を決めずに着手すると、コストの高い施策をやり切ったのに体感は改善しないという悲劇になる。
この記事では web.dev / Chrome for Developers / W3C Web Performance WG の一次資料を引きながら、LCP → INP → CLS の順序で潰す根拠 と、Lighthouse をどう位置付けるか を運用に落とせる粒度で整理する。
Lighthouse 100 点 ≠ 体感速度
Lighthouse は Lab 環境(合成計測) のスコアだ。固定された CPU・ネットワーク条件で計測するため、再現性が高い反面、実ユーザーの体験とは乖離する。Chrome for Developers のLighthouse Performance ドキュメント でも「Lab data is not always representative of what real users experience」と明記されている。
Lab 値で 100 点でも、実機で広告タグが重ければ INP は崩壊する。逆に Lab 値が 70 点でも、ファーストビューが速ければ CWV は Good になりうる。
「全部やる」が最悪手の理由
性能改善のタスクは大量にある。バンドル分割・遅延読み込み・画像 WebP 化・CDN・preload・preconnect・hydration 戦略・SSR/ISR 切替・ServiceWorker・クライアントキャッシュ。全部リスト化して並行で着手すると、どれが効いたかが切り分けられず、PR レビューも詰まる。
優先度を決めずに動くチームは、3 か月後に「結局どれが効いたか分からないけど Lighthouse は上がりました」というレポートしか残らない。
改善順序の根拠 ― Core Web Vitals が示す優先度
CWV 公式の3指標と閾値(web.dev 引用)
web.dev / Core Web Vitals が定義するユーザー体感の代表指標は次の 3 つだ。
| 指標 | 体感する場面 | Good 閾値(web.dev 公式値) | 計測タイミング |
|---|---|---|---|
| LCP (Largest Contentful Paint) | 最初の主要コンテンツが見えるまで | 2.5 秒以下 | ロード時 |
| INP (Interaction to Next Paint) | クリック/タップ後の反応速度 | 200 ms 以下 | インタラクション全体 |
| CLS (Cumulative Layout Shift) | 表示中のレイアウトずれ | 0.1 以下 | ロード〜可視期間 |
注: 上表の閾値はすべて web.dev 公式の「Good」基準を引いている。Needs Improvement / Poor の閾値は元記事を参照のこと。
INP は 2024 年 3 月から CWV 入り
旧指標 FID(First Input Delay)は 2024-03-12 に INP に置き換わった(Chrome for Developers 公式アナウンス)。FID は「最初のクリック1回」しか見ていなかったが、INP は ページ滞在中の全インタラクション を評価する。SPA や hydration 重めのサイトでは数値が劇的に悪化することがある。
ラベル付き断言: 「INP の Good 閾値は 200 ms」は web.dev / developer.chrome.com 双方で 2026 年時点も維持されている公式値。
比較表: LCP / INP / CLS の主要原因と打ち手
| 指標 | 主要原因(経験則: 実務で大半を占める傾向) | 主要打ち手 Top 3 |
|---|---|---|
| LCP | TTFB 遅延 / Hero 画像未最適化 / レンダリングブロック JS-CSS | (1) <img fetchpriority="high"> (2) preload + preconnect (3) SSR/Edge で TTFB 短縮 |
| INP | Long Tasks / hydration / 重いイベントハンドラ | (1) hydration の遅延化 (2) requestIdleCallback でメイン以外を後送り (3) サードパーティ JS の async/defer |
| CLS | 画像/iframe の高さ未指定 / Web Font の swap / 後挿入広告 | (1) width/height 必須 (2) font-display: optional/swap 戦略 (3) 広告枠の reserve |
H2 ごとの根拠: Optimize LCP / Optimize INP / Optimize CLS を一次ソースとした。
改善順序のフロー
flowchart TD
A[ステップ0: RUM で現実を測る] --> B[ステップ1: LCP を最初に潰す]
B --> C[ステップ2: INP で体感を上げる]
C --> D[ステップ3: CLS は最後に微調整]
D --> E[Lighthouse は仕上げの監視]
A:::root
B:::primary
C:::primary
D:::secondary
E:::tool
classDef root fill:#f96,stroke:#333,stroke-width:3px,color:#000
classDef primary fill:#fd9,stroke:#333,stroke-width:2px,color:#000
classDef secondary fill:#fcc,stroke:#333,stroke-width:2px,color:#000
classDef tool fill:#ccf,stroke:#333,stroke-width:2px,color:#000
読み方: RUM が前提で、その上に LCP → INP → CLS が積み上がる。Lighthouse は順序を決めた 後 の補助ツールであり、出発点ではない。
ステップ0: RUM で現実を測る(Lab だけで判断しない)
Lab(Lighthouse) と Field(RUM) の違い
| 観点 | Lab (Lighthouse) | Field (RUM) |
|---|---|---|
| 計測対象 | 開発者の手元/CI の合成環境 | 実ユーザーのブラウザ |
| 再現性 | 高い | 低い(端末/回線/地域でバラつく) |
| 何が分かるか | 「直したいバグ」の発見 | 「実際にユーザーが困っているか」 |
| CWV 評価 | 参考値 | 公式評価対象(web.dev/articles/vitals) |
Field の代表データソースは CrUX (Chrome User Experience Report) だ。Search Console の Core Web Vitals レポート、PageSpeed Insights の「Real-world data」欄も CrUX を引いている。
CrUX を使った最低限の RUM 取得
CrUX は無料で誰でも見られる。https://pagespeed.web.dev/?url=<対象URL> を叩くと Field データ(28日ロール集計)と Lab データの両方が並んで出る。Lab 値と Field 値が乖離していたら、Field を信じる。
社内ダッシュボードに RUM を載せる場合は、CrUX API か web-vitals JS ライブラリ を使うのが定番だ。サンプルコードはリポジトリの README が最も最新で正確なので、そちらを参照してほしい。
体感と Lighthouse スコアが乖離する典型パターン
- 開発機 (M1/M2 Mac + 光回線) では速いが、実ユーザー (中位 Android + 4G) では遅い
- Lighthouse は cookie/権限ダイアログを出さない初回ロードを計測するが、実ユーザーは同意モーダル後の遅延を食う
- 広告/タグマネージャの遅延読み込みが Lab では発火しない
→ Lab 値を見る前に Field 値を確認する が鉄則だ。
ステップ1: LCP を最初に潰す
LCP が最優先な理由(離脱への直結性)
LCP は 「主要コンテンツが見えるまでの時間」 を測る。ユーザーが「このサイト遅い」と感じる第一印象そのものだ。HTTP Archive Web Almanac 2024 Performance 章 でも、LCP は離脱率との相関が他指標より強いと報告されている(2024 年集計)。
主要ボトルネック: TTFB / リソース優先度 / レンダリングブロック
LCP を悪化させる三大要因は次の通り。
- TTFB (Time To First Byte) が遅い: サーバ応答が遅ければ何も始まらない
- Hero 画像のリソース優先度が低い: ブラウザは賢いが、
fetchpriorityでヒントを出さないと出遅れる - レンダリングブロック CSS/JS: head 内の同期 JS / 巨大 CSS が描画を止める
よく効く打ち手 Top 3(コード例つき)
(1) Hero 画像に fetchpriority="high" を付ける
<img
src="/images/hero.webp"
width="1200"
height="630"
alt="ヒーロー画像"
fetchpriority="high"
/>
web.dev / Optimize LCP によると、Hero 画像の fetchpriority="high" 指定は LCP を大きく改善することがあると公式に紹介されている(具体的な改善幅はサイトの構成次第)。
(2) 重要な外部オリジンに preconnect
<link rel="preconnect" href="https://images.example.com" crossorigin />
<link rel="preload" as="image" href="/images/hero.webp" />
(3) SSR / Edge レンダリングで TTFB を短縮
CSR で API を待ってから描画している構成は LCP が構造的に伸びる。SSR / SSG / Edge で TTFB を 100〜300 ms 削れば、LCP の上限がそのまま下がる。
ステップ2: INP で体感を上げる
INP は「ユーザーの行動」に直結する
LCP が改善できたら、次は クリック/タップに対する反応速度(INP) だ。LCP が良くても INP が悪いと、ユーザーは「読み込みは速いがボタンが固まる」と感じる。これは離脱より深刻な「サービスへの不信」を生む。
主要ボトルネック: Long Tasks / hydration / イベントハンドラ
web.dev / Optimize INP と WICG Long Animation Frames API を踏まえると、INP 悪化の主因は次の通り。
- Long Tasks: 50 ms を超える同期処理がメインスレッドを止める
- hydration の同期処理: SSR の HTML をクライアントで賢くするフェーズが重い
- イベントハンドラ内での重い処理: クリック直後に同期で重い計算をしている
よく効く打ち手 Top 3
(1) hydration を遅延化する
React 18+ や Next.js なら <Suspense> / loading.tsx / Server Components で「最初に hydrate する範囲」を絞る。インタラクションのある部分だけ先に hydrate する戦略が有効だ。
(2) 非クリティカルな処理を requestIdleCallback に逃がす
function logAnalytics(payload) {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => sendBeacon(payload), { timeout: 2000 });
} else {
setTimeout(() => sendBeacon(payload), 0);
}
}
クリックハンドラ内で同期に分析イベントを送っているコードは、INP 悪化の典型パターンだ。
(3) サードパーティ JS を async / defer に揃える(依存順検証必須)
タグマネージャ・チャット・A/B ツール・広告 SDK などの同期 JS は、可能な限り async または defer に揃える。発火タイミングをずらすだけで Long Tasks が大きく減る。
⚠ 危険な単純化に注意: タグマネージャ・A/B テスト・同意管理(CMP)・広告 SDK の一部は実行順序や同期実行を前提にしているため、検証なしで一括 async/defer 化すると 計測欠損・同意制御の破綻・広告収益低下を招く。検証環境で「依存順」「発火条件」「計測欠損率」を確認してから本番に適用する。
ステップ3: CLS は最後に微調整
CLS の特性: 直すのは比較的安い
CLS は「視覚の安定性」を測る指標で、直すコストは LCP/INP より明確に低い。原因の多くが「サイズ未指定」「Web Font の swap」「広告枠の差し込み」と限定的なので、最後にまとめて潰すのが効率的だ。
主要ボトルネック
web.dev / Optimize CLS のチェックリスト準拠で、現場で頻出するのは次の 3 つ。
- 画像/iframe の
width/height未指定 → ブラウザが高さを後から確定するためレイアウトがずれる - Web Font の FOIT/FOUT →
font-displayの選択次第でレイアウトずれが起きる - 後挿入される要素(広告・通知バナー・遅延コンポーネント)がリザーブされていない
よく効く打ち手 Top 3
- 画像/iframe に必ず
widthheightを入れる: 単純だが効果が大きい font-display: optionalまたはswapを選択: 完璧な見た目を捨てる代わりに CLS を抑える- 広告/バナー枠は
min-heightで領域確保: コンテンツが押し下げられない設計にする
Lighthouse は「順序を決めた後」の補助ツール
Lighthouse の Opportunities を読み解く順序
Lighthouse の Performance タブには「Opportunities(改善機会)」と「Diagnostics(診断)」が並ぶ。順序を間違えると小さな改善に時間を使ってしまう。
| Lighthouse の指摘 | 対応する CWV | 優先度 |
|---|---|---|
| Largest Contentful Paint element | LCP | 最優先 |
| Total Blocking Time / Long main-thread tasks | INP | 高 |
| Avoid large layout shifts | CLS | 中 |
| Reduce unused JavaScript | LCP/INP 改善の手段 | 中 |
| Properly size images | LCP | 中 |
| Eliminate render-blocking resources | LCP | 高 |
CI に組み込む場合のしきい値の置き方
Lighthouse CI(公式ドキュメント)で PR ごとにスコアを測る場合、しきい値は 「Lab 値の絶対点」ではなく「変動幅」 で置くのが運用しやすい。
- 例: LCP の Lab 値が前回比 +500 ms 以上劣化したら警告
- 例: 各 Performance スコアの絶対値ではなく「main 比 -5 点」で fail
絶対値で 90 点を要求すると、毎回ガチャに振り回される。
改善優先度チェックリスト(12項目)
自プロダクトの状態を診断する 12 項目だ。該当しない(=未対応)が多い項目から着手する。
RUM / 計測
- CrUX or web-vitals.js で Field データを継続収集 している
- PageSpeed Insights を Lab だけでなく Field 値も見ている
- CWV のしきい値(LCP 2.5s / INP 200ms / CLS 0.1)を社内 KPI に書いてある
LCP
- Hero 画像に
fetchpriority="high"とwidth/heightが入っている - 重要な外部オリジンに
preconnect/preloadを貼っている - SSR / Edge で TTFB が 200 ms 以内に収まっている
INP
- hydration の範囲を Server Components / Suspense で絞っている
- 分析・ロギングを
requestIdleCallback等でメインスレッドから逃がしている - サードパーティ JS は
async/deferに揃っている
CLS
- 全ての
<img>/<iframe>にwidth/heightがある - Web Font の
font-display戦略をチームで決めている - 後挿入される広告 / バナー枠は領域がリザーブされている
12 項目中 8 項目以上未対応なら、まず RUM の導入から着手 してほしい。順序を決められない状態で打ち手を増やすと、結果として遅くなる。
ありがちな失敗パターン
失敗1: バンドル削減から入る
「フロントが遅い = JS が重い」と決めつけて、まず webpack/Rollup のチューニングを始めるパターン。バンドル削減は LCP 改善手段の一つに過ぎない。Hero 画像が 2 MB だったり TTFB が 1 秒だったりすると、JS を半分にしても LCP は動かない。
失敗2: Lighthouse スコアを KPI にする
Lab 値が KPI になると、開発機での再現性ばかり追って 本番ユーザー体感を見ない 文化になる。社内 KPI は Field 値(CWV Good 率、LCP p75 など)に置き換えるべきだ。
失敗3: RUM を見ずに Lab のみで判断する
Lab 値だけ見ているチームは、地域差・端末差・回線差をすべて見落とす。日本のスマホユーザーは 4G/5G が混在するため、Lab 値が良くても Field の Poor 率が 20% を超えるケースが起こり得る(経験則。実際の率はサイトと CrUX の母集団に依存)。
なお、本番監視を底上げする観点はeBPF で観測性を底上げするで別の角度から触れている。
LCP 改善の構造的アプローチとして Server / Render 側に手を入れる選択肢もある。Next.js を使っているチームは、Next.js Cache Components 移行設計 で扱う 'use cache' directive と PPR の組み合わせで、TTFB / 静的シェル配信を底上げできる。境界設計の前提として「どの Component を Server にするか」は RSCとClient境界の引き方 で4軸の判断テンプレを示している。
まとめ ― 順序が ROI を決める
フロント性能改善で消耗するチームと、サクッと CWV Good に届けるチームの差は、打ち手の量ではなく順序の決め方 にある。
- まず RUM で現実を測る(Lab だけで判断しない)
- LCP → INP → CLS の順 に潰す(本記事の実務的推奨。公式 CWV は3指標の定義と Good 閾値を提示するが、改善順序までは指定しない)
- Lighthouse は仕上げの監視(Field 値の前に Lab 値を KPI にしない)
⚠ 例外条件: 既に重大なレイアウトシフト(広告枠・モーダル・誤タップ起因)でコンバージョンに直結する CLS 悪化があるサイトは、CLS を後回しにせず先に直す。SPA・ダッシュボード系で来訪直後にクリック/タップが必須なケースは LCP と INP を同時にウォッチする。
この 3 行を運用ルールとして守るだけで、改善 ROI が変わる経験則がある。コンテンツ側の体感速度を上げる土台としても効くので、AI 検索時代のコンテンツ設計と組み合わせて運用するチームが増えている。
なお 3D 描画・ML 推論・GPU compute をブラウザ側で扱うアプリでは、WebGPU の採否が CWV と密接に絡む。ブラウザ対応の現在地は WebGPU実用化の現在地と落とし穴 で整理した。
末尾のチェックリストをチームの定例に持ち込んで、未対応の多い順に 1 つずつ潰す のが最短ルートだ。
次に読むべき記事
- AI 検索時代のコンテンツ設計 ― 体感速度がコンテンツ流通に与える影響
- eBPF で観測性を底上げする ― Field 計測の延長として本番観測性を強化する話
FAQ
Q1. LCP と INP、どちらを先に改善すべきですか?
A. 原則 LCP が先です。LCP はユーザーの第一印象(読み込み体感)を決め、ここで離脱されると INP の機会すら来ないためです。LCP を Good に乗せた後に INP に移る運用がおすすめです。例外として「サイトに来てまずクリック/タップが必要」な SPA・ダッシュボード系は、LCP と INP を同時にウォッチする方が安全です。
Q2. Lighthouse スコアが高いのに体感が遅いのはなぜですか?
A. Lighthouse は Lab 環境(合成計測)で計測した値であり、実ユーザーの端末・回線・サードパーティ JS 状況を反映しないためです。Chrome for Developers 公式 も「Lab data is not always representative of what real users experience」と明記しています。CrUX や web-vitals.js で Field 値を取り、必要なら Field 値を社内 KPI にしてください。
Q3. INP はいつから Core Web Vital になりましたか?
A. 2024 年 3 月 12 日です(Chrome for Developers 公式)。それまで使われていた FID(First Input Delay)は同日付で置き換えられました。FID 時代の知識のままだと「最初の 1 クリックさえ速ければ良い」と勘違いしがちですが、INP は ページ滞在中の全インタラクション を評価します。
Q4. CLS は何点以下なら大丈夫ですか?
A. web.dev 公式の Good 閾値は 0.1 以下です。Needs Improvement は 0.1〜0.25、Poor は 0.25 超です。CLS は直すコストが LCP/INP より低いので、まず画像・iframe・広告枠のサイズ予約から着手すれば 0.1 以下に乗ることが多いです。
Q5. RUM を入れる予算がない場合は何を見れば良いですか?
A. 無料で使える PageSpeed Insights と Search Console の Core Web Vitals レポートから始めてください。両方とも CrUX を引いており、Field 値が無料で見られます。本番に web-vitals.js を埋めて自社のログ基盤に投げる場合でも、追加コストは送信エンドポイント分だけです。
参考文献
- web.dev / Core Web Vitals ― CWV の公式定義と Good 閾値
- web.dev / Optimize LCP ― LCP 主要原因と改善策
- web.dev / Optimize INP ― INP 主要原因と改善策
- web.dev / Optimize CLS ― CLS 主要原因と改善策
- Chrome for Developers / Lighthouse Performance ― Lab 計測の公式ドキュメント
- Chrome for Developers / INP became a Core Web Vital (2024-03-12) ― FID → INP 切替アナウンス
- W3C Web Performance Working Group ― Web パフォーマンス系 W3C 仕様の元
- WICG / Long Animation Frames API ― INP 悪化要因(Long Tasks)の最新仕様
- HTTP Archive / Web Almanac 2024 Performance ― 2024 年の Web パフォーマンス全体動向
相談導線(CTA)
このチェックリストをチームに展開して、最初の 1 項目だけ着手 から始めてみてほしい。「LCP / INP / CLS どれから潰すか迷う」「自社の RUM 設計を相談したい」というケースは、X の DM などで気軽に投げてもらえれば一緒に並べ替えを考えられる。
