LCP最適化:表示速度を改善する方法

LCP要素、そのリソース、配信経路を診断し、フィールドデータとラボデータで対象ルートの改善を確認する方法。

Largest Contentful Paint(LCP)は、2021年からGoogleの検索順位に影響しているCore Web Vitalsの指標です。単なる技術的な数値ではなく、ユーザーがページを読み込み完了と感じるまでの速さを表します。LCPが悪いと、訪問者は空白の画面や読み込み前のメイン画像を見て、コンテンツが表示される前に離脱します。

読み込みのタイムライン:LCPは、ビューポート内で最大の要素が描画された時点で記録されます。目標は、2.5秒未満の緑のゾーンに入ることです。
Googleによると、LCPを「不良」から「良好」に改善すると、直帰率が平均24%下がります。ECサイトでは、コンバージョンに直結します。

LCPとは、なぜ重要か

LCPは、ナビゲーション開始から、最大のコンテンツ要素(テキストまたは画像)がビューポート内に表示されるまでの時間を測ります。Googleはこの時点を、ユーザー体験から見て読み込みが「完了」した目安としています。

最初の1ピクセルで記録されるFCP(First Contentful Paint)と違い、LCPは意味のあるコンテンツを対象にします。0.3秒でスピナーが出ても、メイン画像が5秒で表示されれば、LCPは5秒です。

2.5秒未満

良好なLCP

Googleの緑の基準。ほとんどのページの目標です

2.5〜4秒

改善が必要

黄色のゾーン。ユーザーがLCPを体感するため、最適化が必要です

4秒超

不良なLCP

赤のゾーン。UXと検索順位に大きなダメージがあります

75パーセンタイル

CrUXのパーセンタイル

Googleは、実際のChromeユーザーの75パーセンタイル値でLCPを評価します

Googleが使うのは、Chrome User Experience Report(CrUX)のデータです。実際のChromeユーザーによる実測値です。PageSpeed Insightsのラボスコアは緑でも、CrUXは黄色ということがあります。見るべきはCrUXのフィールドデータです。Googleが順位の判断に使うのはこちらです。

ブラウザがLCPの候補とみなす要素

ブラウザは、すべての要素を追跡するわけではありません。対象は特定の種類の要素で、読み込みが完了した時点でビューポート内の面積が最大のものが選ばれます。

<img>要素
標準の画像です。多くのページで最も一般的なLCP候補です。時間は、デコード済みの画像がビューポートに表示された時点です。
SVG内の<image>
SVG要素の中の画像です。LCPでは通常のimg要素と同じ扱いです。
CSSのbackground-image
CSSで指定する背景画像です。ブラウザは、CSSOMが構築されるまでbackground-imageの読み込みを始めません。これがLCP遅延の主な原因の1つです。
テキストブロック
<p>、<h1>〜<h6>、<div>など、テキストを含む要素です。テキストブロックがどの画像より大きければ、それがLCPになります。
posterを指定した<video>
video要素のポスターフレーム(poster属性)です。動画が画面の大部分を占める場合、ポスターはできるだけ速く読み込む必要があります。
<iframe>内の要素と、表示サイズのない要素(display: none、visibility: hidden、opacity: 0)は、LCPの対象になりません。JSの初期化前にメインバナーが隠れていると、LCPがまったく別の要素で計測されることがあります。

LCPの時間の内訳

GoogleはLCPを4つのサブコンポーネントに分解しています。それぞれを理解すると、診断と最適化の優先順位を正しく付けられます。

コンポーネント計測対象一般的な割合
TTFB(最初のバイトまでの時間)サーバーからHTMLの最初のバイトが届くまでの時間10〜40%
Resource Load DelayTTFBから、LCPリソースの読み込み開始までの間10〜30%
Resource Load DurationLCPリソース自体(画像、フォント)のダウンロード時間30〜60%
Element Render Delayリソースの読み込み完了から、ビューポートに表示されるまでの間0〜20%

ルールは、最も割合の大きいコンポーネントから手を付けることです。LCP 5秒のうちTTFBが3秒なら、画像を最適化しても効果はわずかです。先にサーバーの応答時間を直します。

LCPが遅くなる主な原因

LCPが悪いケースの90%は、同じ根本原因を共有しています。診断は、DevToolsかPageSpeed Insightsで15分ほどで終わります。

TTFBが遅い

サーバーの応答に600ミリ秒より長くかかります。原因は、キャッシュなし、非力なホスティング、重いデータベースクエリ、CDNなしなどです。TTFBが800ミリ秒を超えると、ほかの最適化なしでLCP 2.5秒未満を達成するのはほぼ不可能です。

画像が最適化されていない

LCP画像が、WebP/AVIFなら80KBのところ、JPEGで500KB以上あります。fetchpriority="high"属性もpreloadもありません。ブラウザが画像を見つけるのが遅れ、読み込みも遅くなります。

レンダリングをブロックするリソース

<head>内でasync/deferのないCSSとJSは、レンダリングをブロックします。ブラウザがそれらを読み込んで実行するまで、LCP要素は表示されません。headにスクリプトが1つ増えるたびに遅延が増えます。

フォントの読み込みが遅い

LCPがテキストブロックで、フォントの読み込みに2秒以上かかると、ブラウザはFOIT(テキストが見えない状態)かFOUT(システムフォント)を表示します。正しいテキストが表示されるまでの時間が、そのままLCPになります。

LCP要素への遅延読み込み

メイン画像のloading="lazy"属性は、最もよくある間違いの1つです。ブラウザが意図的に読み込みを遅らせるため、LCPに直接響きます。

クライアントサイドレンダリングでのLCP

SSRのないSPA(React、Vue、Angular)では、コンテンツがブラウザ上でJavaScriptによって生成されます。ブラウザは空のHTMLを受け取り、JSを読み込んでから、コンテンツをレンダリングします。この流れ全体がLCPに積み上がります。

LCPを最適化する手順

LCPの最適化に、これ1つで効く方法はありません。相互に関係する改善の組み合わせです。効果の大きいものから順に進めます。

ステップ1:TTFBを200〜400ミリ秒に短縮する

TTFBは土台です。サーバーが遅いと、ほかの最適化はその上限に縛られます。

  1. HTTPキャッシュを設定します。静的アセットにはCache-Control: max-age=31536000、CDNプロキシにはs-maxageを指定します。
  2. 圧縮を有効にします。HTML、CSS、JSにはBrotli(推奨)かgzipを使います。Brotliはgzipよりファイルが15〜25%小さくなります。
  3. CDNを導入します。Cloudflare、Fastly、BunnyCDNなどです。静的サイトなら、エッジキャッシュでTTFBが20〜50ミリ秒になります。
  4. データベースを最適化します。よく検索するフィールドにインデックスを張り、RedisかMemcachedでクエリをキャッシュします。
  5. HTTP/2かHTTP/3を使います。1つの接続で複数のリクエストを処理でき、head-of-line blockingも起きません。
TTFBの目標は、サーバー+CDNで200ミリ秒未満です。Nginx+静的HTML+CDNの構成なら達成できます。キャッシュなしのPHP/Nodeでデータベースクエリをその都度実行しているなら、先にアプリケーション側の最適化が必要です。

ステップ2:LCP画像を最適化する

LCP要素が画像(メイン画像、商品画像)なら、費用対効果の高い最適化がいくつもあります。

  • 最新のフォーマットに変換します。WebP(JPEG比で25〜35%削減)かAVIF(JPEG比で40〜55%削減)です。フォールバック付きの<picture>を使います。
  • LCP画像にfetchpriority="high"を付けます。ブラウザが最優先で読み込みます。
  • LCP要素からloading="lazy"を外します。遅延読み込みは、最初のビューポートより下にある画像にだけ使います。
  • LCP画像用に、<head>へ<link rel="preload" as="image">を追加します。bodyの解析前に読み込みが始まります。
  • widthとheight属性を指定して、CLSを防ぎます。画像の読み込み前に、ブラウザが領域を確保します。
  • srcsetとsizesを設定して、レスポンシブに読み込みます。モバイルには1600pxではなく400pxの画像が届きます。
fetchpriority="high"、preload、WebP/AVIF、適切なsrcsetを組み合わせると、実際のECプロジェクトでLCPが平均1〜2秒改善します。

ステップ3:レンダリングをブロックするリソースをなくす

レンダリングをブロックするリソースは、1つ増えるごとにLCPを遅らせます。目標は、クリティカルパスにブロックするリソースを置かないことです。

リソースの種類問題対策
<head>内のJavaScriptブラウザがHTMLの解析を止めてスクリプトを実行する重要でないスクリプトすべてにdeferかasyncを付ける
<head>内のCSSすべてのCSSを読み込むまで、ブラウザは何も描画しないクリティカルCSSをインライン化し、それ以外はasyncのloadCSSで読み込む
サードパーティのスクリプトアナリティクス、チャットボット、ピクセルがheadで読み込まれるbodyに移すか、遅延させて読み込む(setTimeout 3000)
preloadのないフォントブラウザがフォントを見つけるのは、CSSを解析した後になる<link rel="preload" as="font">とfont-display: swap

ステップ4:フォントを最適化する(LCPがテキストの場合)

LCP要素がテキストブロック(見出し、リード文)のとき、問題はフォントの描画遅延であることがよくあります。

  1. @font-faceにfont-display: swapかoptionalを追加します。ブラウザはまずシステムフォントを表示し、読み込み後にカスタムフォントへ切り替えます。
  2. 重要なフォントには、<head>に<link rel="preload" as="font" type="font/woff2" crossorigin>を置きます。
  3. 文字セットを絞ります。サブセット化して、必要なグリフ(ラテン文字、キリル文字)だけを読み込みます。
  4. Google Fontsから読み込まず、フォントをセルフホストします。DNSルックアップと接続が1回減ります。
  5. @font-faceにsize-adjust、ascent-override、descent-overrideを設定して、フォント切り替え時のCLSを抑えます。

ステップ5:JavaScriptフレームワークではSSR/SSGを使う

ReactやVue、SSRなしのNext.jsでサイトを動かしていると、LCPは最初から高くなります。ブラウザがJavaScriptをダウンロードして実行し、それからやっとコンテンツをレンダリングするためです。

Server-Side Rendering(SSR)
リクエストごとにサーバーでHTMLを生成します。ブラウザは完成したHTMLを受け取って解析し、JSを待たずにLCP要素が表示されます。動的なコンテンツに最適な方法です。
Static Site Generation(SSG)
ビルド時にHTMLを生成します。サーバーは完成したファイルを返すだけなので、TTFBとLCPが最速になります。ブログ、ランディングページ、パーソナライズしないページに向いています。
Incremental Static Regeneration(ISR)
定期的に再生成するSSG(Next.js)です。静的ファイルの速さとデータの新しさを両立します。多くのCMSコンテンツに最適です。
Streaming SSR
レンダリングの完了前から、サーバーがHTMLを送り始めます。ブラウザはコンテンツを順に表示します。React 18とNext.js 13以降は、設定なしで対応しています。
Partial HydrationとIslands Architecture(Astro、Qwik)は、さらに効果的な方法です。ハイドレーションするのはインタラクティブなコンポーネントだけで、静的なコンテンツは即座にレンダリングされます。コンテンツ中心のサイトでは、LCPが0.5〜1秒改善します。

ステップ6:CSSのbackground-imageがLCPの場合

LCP要素にCSSのbackground-imageを使っていると、ブラウザはCSSOMが構築されるまで読み込みを始められません。LCPが遅くなる原因の中でも、特に気づきにくいものの1つです。

  • CSSのbackground-imageを<img fetchpriority="high">に置き換えます。ブラウザがHTMLの解析中に見つけられます。
  • 置き換えられない場合は、<link rel="preload" as="image">で読み込みを手動で開始します。
  • レスポンシブな背景には、preloadタグでimagesrcsetとimagesizesを使います。
  • LCPのbackground-imageを含むCSSを、インラインの<style>に移します。ネットワークリクエストが1回減ります。

LCPを計測・診断するツール

やみくもな最適化より、正しい診断が大切です。ラボ(合成テスト)とフィールド(実ユーザー)、両方のツールを使います。

ツールデータの種類分かること使う場面
PageSpeed Insightsラボ+フィールド(CrUX)LCPスコア、サブコンポーネントの内訳、具体的な改善提案最初の監査、変更の確認
Chrome DevTools Performanceラボ読み込みのウォーターフォール、LCP遅延の正確な原因、フレームチャート特定の問題の詳細な診断
Lighthouse CIラボCI/CDでの自動チェック、リリースごとのLCP履歴リグレッションの監視
WebPageTestラボ複数リージョンからのテスト、動画比較、フィルムストリップ、ウォーターフォールCDNの確認、地域別のLCP
Google Search Console(CWV)フィールド(CrUX)URLグループ別の実際のLCP、問題のあるページ本番環境のモニタリング
web-vitals.jsフィールド実ユーザーのLCPを独自のアナリティクスに集めるJavaScript API独自のモニタリング、RUM

Chrome DevToolsでLCPを診断する方法

DevToolsは、特定のページでLCPを遅らせている原因を突き止めるのに、最も正確なツールです。

  1. DevToolsを開き、Performanceで録画を開始し、ページを再読み込みして、録画を止めます。
  2. Timingsで、LCPのマーカーを探します。正確な時間と要素が表示されます。
  3. ウォーターフォールを見ます。LCP要素のリソースを見つけ、TTFBに対して読み込みがいつ始まったかを確認します。
  4. 赤いバーを探します。レンダリングをブロックするリソースで、LCPの直前に現れます。
  5. Networkタブでタイプを「Image」に絞り、LCP画像を見つけて優先度を確認します(Highのはずです)。
  6. Coverageタブで、使われていないCSS/JSを確認します。未使用のコードが多いと、LCPの遅延につながります。
DevToolsのNetworkでは、LCP画像のPriorityがHigh、InitiatorがPreloadかParser(スクリプトではない)になっているはずです。InitiatorがスクリプトやXHRなら、画像を見つけるのが遅すぎます。

FAQ

LCPがPageSpeed Insightsでは「緑」なのに、Search Consoleでは「赤」なのはなぜですか?
PageSpeed Insightsは、ラボデータ(Lighthouse)とフィールドデータ(CrUX)の両方を表示します。緑なら、Lighthouseのスコアを見ている可能性があります。PSIとSearch ConsoleのCrUXは、実際のChromeユーザーを反映しています。接続が遅い、端末が古い、地域が違うといったユーザーも含まれます。見るのは常にCrUX/フィールドデータです。Googleが順位に使うのはこちらです。
コードを変えずにLCPを改善できますか?
一部は可能です。CDNの導入、HTTPキャッシュの設定、Brotli圧縮の有効化は、サーバー設定の変更です。画像のWebP/AVIFへの変換と圧縮も、サイトのコード変更が不要です。ただし、fetchpriority、preload、メイン画像からの遅延読み込みの削除、SSRは、いずれもコードの変更が必要です。
LCPが画像ではなくテキストの場合は?
フォントとTTFBに注目します。Webフォントにpreloadを追加し、font-display: swapを使い、フォントをセルフホストします。テキストが大きなブロックにあり、クリティカルCSSがない場合は、そのブロックに影響するCSSがレンダリングをブロックしていないか確認します。TTFBも確認してください。画像がなくても、サーバーが遅ければLCPは高くなります。
LCPは検索順位に直接影響しますか?
影響します。LCPは、2021年からGoogleが公式にランキング要因として使っているページエクスペリエンスのシグナル、Core Web Vitalsの一部です。LCPが悪くても順位が急落するわけではありませんが、ほかの条件が同じなら、LCPが良いサイトが有利です。効果が最もはっきり出るのはモバイルです。
LCPの最適化は、全ページで必要ですか?トップページだけでよいですか?
オーガニックのトラフィックが多いページと、有料広告のランディングページを優先します。Google Search Consoleで「不良」のLCPと判定されたURLが分かるので、そこから始めます。ECでは、トップページ、カテゴリページ、商品ページが先になるのが一般的です。フォントやCDN、Brotliといった技術的な改善は、サイト全体に効きます。

Check it with SpiderHead

Free and local: run the audit on your own machine.

Try it