Largest Contentful Paint を最適化する

Largest Contentful Paint(LCP)は、3 つの Core Web Vitals 指標のうちの 1 つです。ウェブページのメイン コンテンツの読み込みにかかった時間を表します。具体的には、ユーザーがページの読み込みを開始してから、最大の画像やテキスト ブロックがビューポート内にレンダリングされるまでの時間を表します。

優れたユーザー エクスペリエンスを提供するため、サイトの LCP はページアクセスの 75% 以上で 2.5 秒以下である必要があります。

良好な LCP 値は 2.5 秒以下、不良値は 4.0 秒超で、この間は改善が必要
適切な LCP 値は 2.5 秒以下です。

ブラウザでのウェブページの読み込みとレンダリングの速度にはさまざまな要因が影響し、どれかひとつの遅延が LCP に重大な影響を及ぼします。

ページのごく一部を短時間で修正しても、LCP が大幅に改善されることはまれです。LCP を改善するには、読み込みプロセス全体を確認し、すべてのステップを最適化する必要があります。

LCP 指標について

LCP を最適化する前に、デベロッパーはサイトに LCP の問題が発生しているかどうか、発生している場合はその程度を把握する必要があります。

LCP は多くのツールで測定できますが、すべてのツールで同じ方法で測定できるわけではありません。実際のユーザーの LCP エクスペリエンスを理解するには、Lighthouse やローカルテストなどのラボベースのツールで示される内容だけでなく、実際のユーザー エクスペリエンスを理解する必要があります。これらのラボベースのツールは、LCP の説明や指標の改善に役立つ豊富な情報を提供しますが、ラボテストだけでユーザー エクスペリエンスを完全に表しているわけではありません。

サイトにインストールされた Real User Monitoring(RUM)ツールや、何百万ものウェブサイトの実際の Chrome ユーザーから匿名データを収集する Chrome ユーザー エクスペリエンス レポート(CrUX)を介して、実際のユーザーに基づく LCP データを表示できます。

PageSpeed Insights で CrUX データを使用する

PageSpeed Insights では、「実際のユーザーが体験している状況を確認する」セクションで CrUX のデータにアクセスできます。ラボベースのデータの詳細については、パフォーマンスの問題を診断するをご覧ください。利用可能な場合は、常に CrUX データに焦点を合わせます。

PageSpeed Insights に表示される CrUX データ
PageSpeed Insights に表示される CrUX データ

CrUX がデータを提供しない場合(トラフィックが不十分でページレベルのデータを取得できない場合など)は、ページ上で実行される JavaScript API を使用して収集した RUM データで CrUX を補完できます。また、CrUX が一般公開データセットとして公開できるデータよりもはるかに多くのデータを提供できます。このガイドの後半では JavaScript を使用して このデータを収集する方法を説明します

LCP データ

PageSpeed Insights には、最大 4 種類の CrUX データセットが表示されます。

  • この URLモバイルデータ
  • この URLパソコンデータ
  • Origin 全体のモバイルデータ
  • Origin 全体のデスクトップデータ

これらは、このセクションの上部と右上のコントロールで切り替えることができます。URL レベルで表示するのに十分なデータがない URL が元のデータを持っている場合、PageSpeed Insights は常に元のデータを表示します。

PageSpeed Insights が URL レベルのデータを利用できないオリジン レベルのデータにフォールバックする
PageSpeed Insights に URL レベルのデータがない場合は、オリジンレベルのデータが表示されます。

オリジン全体の LCP が個々のページの LCP とは大きく異なる場合があります。これは、そのページでの LCP の読み込み方法とそのオリジンの他のページの LCP の読み込み方法によって異なります。また、ユーザーがこれらのページにどのように移動したかによっても影響を受けます。 ホームページは新規ユーザーがアクセスする傾向があるため、キャッシュに保存されたコンテンツなしで読み込まれることが多いため、ホームページはウェブサイトの中で最も遅いページになります。

CrUX データの 4 つの異なるカテゴリを見ると、LCP の問題がこのページに固有のものなのか、それともより一般的なサイト全体の問題なのかを理解するのに役立ちます。同様に、LCP に問題があるデバイスタイプを確認できます。

補足指標

LCP の最適化に取り組むデベロッパーは、First Contentful Paint(FCP)Time to First Byte(TTFB)のタイミングを使用することもできます。これは、LCP に関する貴重な分析情報を得ることができる優れた診断指標です。

TTFB は、訪問者がページ移動(たとえば、リンクのクリック)を開始してから、HTML ドキュメントの最初のバイトを受信するまでの時間です。TTFB が高いと、2.5 秒の LCP を達成することが困難または不可能な場合があります。

TTFB が高い原因としては、複数のサーバー リダイレクトがある、ユーザーが最も近いサイトサーバーから遠くにいる、ユーザーがネットワーク状況が良くない、クエリ パラメータが原因でキャッシュに保存されたコンテンツを利用できないことなどが考えられます。

ページのレンダリングが始まると、最初のペイント(背景色など)が行われ、その後にコンテンツ(サイトのヘッダーなど)が表示されます。初期コンテンツの外観は FCP によって測定され、FCP と他の指標の違いは非常に明らかです。

TTFB と FCP が大きく異なる場合は、ブラウザでレンダリングをブロックするアセットを大量にダウンロードする必要があることを示している可能性があります。また、意味のあるコンテンツをレンダリングするためにブラウザが多くの作業を完了しなければならないことを示している場合もあります。これは、サイトがクライアントサイド レンダリングに大きく依存していることを示唆しています。

FCP と LCP の間に大きな違いがある場合、LCP リソースはブラウザですぐに利用できない(たとえば、最初の HTML では使用できない JavaScript によって管理されるテキストや画像)、LCP コンテンツを表示するにはブラウザで他の処理を完了する必要があることを示します。

PageSpeed Insights の Lighthouse のデータを使用する

PageSpeed Insights の Lighthouse セクションでは、LCP を改善するためのガイダンスがいくつか提示されていますが、まず、提供されている LCP が CrUX が提供する実際のユーザーデータとおおむね一致しているかどうかを確認する必要があります。Lighthouse と CrUX で意見が一致しない場合、CrUX の方がユーザー エクスペリエンスをより正確に予測できる可能性があります。CrUX データが元のページに関するものではなく、ページ全体のデータであることを確認してください。

Lighthouse と CrUX の両方で改善が必要な LCP 値が示された場合、Lighthouse のセクションで、LCP を改善する方法について有益なガイダンスを得ることができます。次のように LCP フィルタを使用して、LCP に関連する監査のみを表示します。

Lighthouse LCP の最適化案と診断ツール
Lighthouse の診断機能と LCP の改善に向けた提案

改善のための改善の機会だけでなく、問題の診断に役立つ詳細な情報を提供する診断情報があります。Largest Contentful Paint 要素の診断では、LCP を構成するさまざまなタイミングについての有用な内訳が表示されます。

Lighthouse LCP フェーズ
Lighthouse による LCP 要素の内訳

次のセクションでは、LCP のサブカテゴリについて詳しく説明します。

LCP の内訳

このセクションでは、LCP を最も重要なサブカテゴリに分類する方法と、各サブカテゴリを最適化するための具体的な推奨事項とベスト プラクティスについて説明します。

通常、ほとんどのページの読み込みには複数のネットワーク リクエストが含まれますが、LCP を改善する機会を特定するには、最初の HTML ドキュメントのみから開始することをおすすめします。また、該当する場合は LCP リソースからも開始することをおすすめします。

ページ上の他のリクエストが LCP に影響を与える可能性がありますが、この 2 つのリクエスト(特に LCP リソースの開始時間と終了時間)によって、ページが LCP 向けに最適化されているかどうかがわかります。

LCP リソースを特定するには、PageSpeed Insights、Chrome DevToolsWebPageTest などのデベロッパー ツールを使用して、LCP 要素を特定します。そこから、ページによって読み込まれるすべてのリソースのネットワーク ウォーターフォールで、要素によって読み込まれた URL(該当する場合)を照合できます。

たとえば、次の可視化では、これらのリソースが一般的なページ読み込みのネットワーク ウォーターフォール図でハイライト表示されています。ここで、LCP 要素はレンダリングに画像リクエストを必要とします。

HTML リソースと LCP リソースがハイライト表示されたネットワーク ウォーターフォール
ウェブページの HTML の読み込み時間と LCP に必要なリソースを示すウォーターフォール図。

十分に最適化されたページでは、LCP リソース リクエストの読み込みをできるだけ早く開始し、LCP リソースの読み込みが完了した後に LCP 要素をできるだけ早くレンダリングする必要があります。特定のページがこの原則に従っているかどうかを可視化するには、合計 LCP 時間を次のサブカテゴリに分類します。

最初のバイトまでの時間(TTFB)
ユーザーがページの読み込みを開始してから、ブラウザが HTML ドキュメント レスポンスの最初のバイトを受け取るまでの時間。
リソース読み込みの遅延
TTFB から、ブラウザが LCP リソースの読み込みを開始するまでの時間。LCP 要素のレンダリングにリソースの読み込みを必要としない場合(たとえば、要素がシステム フォントでレンダリングされるテキストノードの場合)、この時間は 0 です。
リソースの読み込み時間
LCP リソース自体を読み込むのにかかる時間。LCP 要素のレンダリングにリソースの読み込みが必要ない場合、この時間は 0 です。
要素のレンダリング遅延
LCP リソースの読み込みが完了してから、LCP 要素が完全にレンダリングされるまでの時間。

各ページの LCP は、この 4 つのサブカテゴリで構成されます。この 2 つの間にギャップや重複はなく、合計で完全な LCP 時間になります。

4 つのサブカテゴリを示す LCP の内訳
同じウォーターフォール図。4 つの LCP サブカテゴリがタイムラインに重ねて表示されます。

LCP を最適化する場合は、これらのサブカテゴリを最適化することをおすすめします。ただし、最適化によっては、実際に LCP を短縮するのではなく、一部で節約される時間が別の部分に移行されるため、すべてのサブカテゴリを最適化する必要があります。

たとえば、ネットワーク ウォーターフォールの例では、画像の圧縮率を高めるか、より最適な形式(AVIF や WebP など)に切り替えてファイルサイズを縮小すると、リソースの読み込み時間は短縮されますが、その時間が要素のレンダリング遅延の一部になるため、LCP は改善されません。これは、LCP 要素は、関連する JavaScript の読み込みが完了して表示されるまで非表示になるためです。

先ほどの LCP の内訳と同じく、リソース読み込み時間のサブカテゴリが短縮されていますが、全体の LCP 時間は変わりません。
リソースの読み込み時間を短縮すると、LCP を低減することなく要素のレンダリング遅延が増加します。

最適なサブカテゴリの時間

LCP の各サブカテゴリを最適化するには、適切に最適化されたページで、これらのサブカテゴリの理想的な内訳を把握することが重要です。

遅延に関連する 2 つのサブカテゴリは、可能な限り減らす必要があります。他の 2 つのネットワーク リクエストは本質的に時間がかかり、完全に最適化することはできません。

以下に、理想的な LCP 分布を示します。

LCP サブパート LCP の割合
最初のバイトまでの時間(TTFB) ~40%
リソース読み込みの遅延 10% 未満
リソースの読み込み時間 ~40%
要素のレンダリング遅延 10% 未満
合計 100%

この時間はガイドラインであり、厳格なルールではありません。ページの LCP 時間が一貫して 2.5 秒以下の場合、内訳の内容はそれほど重要ではありません。ただし、遅延のカテゴリが不必要に長いと、2.5 秒の目標に到達できなくなります。

LCP 時間の内訳は次のように考えることをおすすめします。

  • LCP の時間の大部分は、HTML ドキュメントと LCP ソースの読み込みに費やされます。
  • LCP の前に、この 2 つのリソースのいずれかが読み込まれない場合は、改善の余地があります。

各カテゴリを最適化する方法

適切に最適化されたページで LCP サブカテゴリの時間がどのようになるかを理解したら、次はページの最適化を開始します。

以降のセクションでは、各カテゴリを最適化する推奨事項とベスト プラクティスについて説明します。最も大きな効果をもたらす可能性のある最適化から順に説明します。

リソースの読み込み遅延を排除する

このステップの目標は、LCP リソースの読み込みをできるだけ早く開始できるようにすることです。理論的には、TTFB の直後にリソースの読み込みを開始することはできますが、ブラウザが実際にリソースの読み込みを開始するまでには、常に多少の遅延が生じます。

目安として、LCP リソースは、ページが最初に読み込まれるリソースと同じ時間に開始するようにします。

LCP リソースが最初のリソースの後に始まっていることを示す、改善の機会を示すネットワークのウォーターフォール図
このページで、最初にスタイルシートが読み込まれた後で、LCP リソースの読み込みが開始されます。まだ改善の余地があります。

一般的に、LCP リソースの読み込み速度に影響を与える要因は次の 2 つです。

  • リソースが検出されたとき。
  • リソースに付与される優先度。

リソースの検出時に最適化する

LCP リソースの読み込みをできるだけ早く開始するには、ブラウザのプリロード スキャナによって、最初の HTML ドキュメント レスポンスでそのリソースを検出できる必要があります。検出可能な LCP リソースの例を次に示します。

  • src 属性または srcset 属性が最初の HTML マークアップに含まれている <img> 要素。
  • CSS の背景画像を必要とする要素。ただし、その画像が HTML マークアップの <link rel="preload"> によって(または Link ヘッダーを使用して)プリロードされている必要があります。
  • レンダリングにウェブフォントが必要なテキストノード。ただし、フォントが HTML マークアップの <link rel="preload"> によって(または Link ヘッダーを使用して)プリロードされている必要があります。

HTML ドキュメントのレスポンスをスキャンしても検出できない LCP リソースは次のとおりです。いずれの場合も、ブラウザは LCP リソースを検出して読み込みを開始する前に、スクリプトを実行するかスタイルシートを適用する必要があります。そのため、ネットワーク リクエストが完了するまで待機する必要があります。

  • JavaScript を使用してページに動的に追加される <img>
  • src 属性または srcset 属性を非表示にする JavaScript ライブラリを使用して遅延読み込みされる要素(多くの場合、data-src または data-srcset)。
  • CSS 背景画像を必要とする要素。

不要なリソースの読み込み遅延をなくすには、LCP リソースが HTML ソースから検出可能である必要があります。リソースが外部の CSS または JavaScript ファイルからのみ参照されている場合は、LCP リソースを高いフェッチ優先度でプリロードする必要があります。次に例を示します。

<!-- Load the stylesheet that will reference the LCP image. -->
<link rel="stylesheet" href="/path/to/styles.css">

<!-- Preload the LCP image with a high fetchpriority so it starts loading with the stylesheet. -->
<link rel="preload" fetchpriority="high" as="image" href="/path/to/hero-image.webp" type="image/webp">

リソースに与えられる優先度を最適化する

LCP リソースが HTML マークアップから検出可能であっても、最初のリソースよりは読み込みが開始されない場合があります。これは、ブラウザ プリロード スキャナの優先度ヒューリスティックが、そのリソースが重要であると認識していない場合、または他のリソースの方が重要であると判断した場合に発生することがあります。

たとえば、<img> 要素で loading="lazy" を設定すると、HTML を使用して LCP 画像を遅らせることができます。遅延読み込みを使用すると、画像がビューポートにあることをレイアウトが確認するまで、リソースは読み込まれません。そのため、通常はそうでない場合よりも後で画像の読み込みが発生します。

遅延読み込みがなくても、ブラウザは最初に優先度の高い画像を読み込まず、これはレンダリングをブロックするリソースではないためです。リソースの読み込み優先度は、次のように fetchpriority 属性を使用して上げることができます。

<img fetchpriority="high" src="/path/to/hero-image.webp">

ページの LCP 要素である可能性が高い場合は、<img> 要素に fetchpriority="high" を設定することをおすすめします。ただし、1 ~ 2 枚以上のイメージに高い優先度を設定すると、優先度の設定は LCP を減らすうえで役に立ちません。

また、ドキュメントのレスポンスの早い段階で表示され、スタイル設定により表示されない画像(起動時に表示されないカルーセル スライドの画像など)の優先度を下げることもできます。

<img fetchpriority="low" src="/path/to/carousel-slide-3.webp">

特定のリソースの優先度を下げると、より多くの帯域幅を必要とするリソースにより多くの帯域幅が提供されますが、過剰にならないよう注意してください。DevTools で常にリソースの優先度を確認し、ラボツールやフィールドツールで変更をテストします。

LCP リソースの優先度と検出時間を最適化すると、ネットワーク ウォーターフォールは次のようになります。LCP リソースは最初のリソースと同じ時間に開始されます。

LCP リソースが最初のリソースと同時に開始されるようになったネットワークのウォーターフォール図
LCP リソースは、スタイルシートと同時に読み込みを開始します。

重要なポイント: LCP リソースが HTML ソースから検出可能であっても、LCP リソースができるだけ早く読み込みを開始しないもう 1 つの理由は、リソースの読み込みを開始する前にブラウザで接続する必要がある別のオリジンに LCP がホストされている場合です。可能であれば、重要なリソースを HTML ドキュメント リソースと同じオリジンでホストすることをおすすめします。これにより、ブラウザは既存の接続を再利用して時間を節約できます(詳しくは後述します)。

要素のレンダリング遅延を排除する

このステップの目標は、リソースの読み込みが完了したタイミングに関係なく、リソースの読み込みが完了した直後に LCP 要素がレンダリングできるようにすることです。

リソースの読み込み完了直後に LCP 要素がレンダリングできない主な理由は、次のような理由でレンダリングがブロックされていることです。

  • ページ全体のレンダリングがブロックされているのは、<head> のスタイルシートまたは同期スクリプトがまだ読み込み中であるためです。
  • LCP リソースの読み込みは完了しましたが、LCP 要素はまだ JavaScript コードの読み込みを待機しているため、DOM に追加されていません。
  • この要素は、ユーザーを追加するテストグループがまだ決定されていない A/B テスト ライブラリなど、他のコードによって非表示になっています。
  • 長いタスクが原因でメインスレッドがブロックされ、レンダリング処理は長いタスクが完了するまで待機する必要があります。

以降のセクションでは、不必要な要素のレンダリング遅延の最も一般的な原因に対処する方法について説明します。

レンダリングをブロックするスタイルシートを削減またはインライン化する

HTML マークアップから読み込まれたスタイルシートは、それに続くすべてのコンテンツのレンダリングをブロックします。このようにすると、他の要素が読み込まれる前にスタイルシートが有効になるため、通常は問題ありません。ただし、スタイルシートが大きすぎて、LCP リソースよりも読み込みに時間がかかる場合は、次の例に示すように、リソースの読み込みが完了しても LCP 要素はレンダリングされません。

LCP 要素の大きな CSS ファイル ブロック レンダリングを示すネットワークのウォーターフォール図(LCP リソースよりも読み込みに時間がかかるため)
画像とスタイルシートの読み込みは同時に開始されますが、スタイルシートの準備が整うまで画像はレンダリングできません。

この問題を解決するには、次のいずれかを行います。

  • スタイルシートを HTML にインライン化して、追加のネットワーク リクエストを回避する。
  • スタイルシートのサイズを縮小します。

スタイルシートのインライン化は、スタイルシートが小さい場合にのみ LCP の低減に有効です。ただし、スタイルシートの読み込みが LCP リソースよりも時間がかかる場合は、サイズが大きすぎてインラインで適切に処理できない可能性があるため、次のようにスタイルシートの複雑さを減らすことをおすすめします。

レンダリングをブロックする JavaScript を遅延またはインライン化する

async 属性または defer 属性を使用して、ページ上のすべてのスクリプトを非同期にすることをおすすめします。同期スクリプトの使用は、ほとんどの場合、パフォーマンスに悪影響を及ぼします。

ただし、ページ読み込みのできるだけ早い段階で JavaScript を実行する必要がある場合は、小さなスクリプトをインライン化することで LCP を改善し、ブラウザがネットワーク リクエストの待機に費やす時間を短縮できます。

推奨事項
<head>
  <script>
    // Inline script contents directly in the HTML.
    // IMPORTANT: only do this for very small scripts.
  </script>
</head>
すべきでないこと
<head>
  <script src="/path/to/main.js"></script>
</head>

サーバーサイド レンダリングを使用する

サーバー側レンダリング(SSR)は、サーバー側でクライアント側アプリケーション ロジックを実行し、完全な HTML マークアップを使用して HTML ドキュメント リクエストに応答するプロセスです。

SSR は、次の方法で LCP を最適化するのに役立ちます。

  • リソース読み込みの遅延をなくすで説明されているように、HTML ソースからリソースを検出できるようになります。
  • これにより、ページをレンダリングする前に追加の JavaScript リクエストを完了する必要がなくなります。

SSR の主な欠点は、サーバー処理時間が増加し、TTFB が遅くなる可能性があることです。ただし、サーバーの処理時間は制御できる一方で、ユーザーのネットワークとデバイスの機能は制御できないため、このトレードオフは通常、それだけの価値があります。

また、パフォーマンスを向上させるため、オンデマンドではなく、ビルドステップで HTML ページを生成することをおすすめします。この手法は、静的サイト生成(SSG)または事前レンダリングと呼ばれます。

長いタスクを分割する

上記の推奨事項をすべて適用しても、JavaScript コードがレンダリングをブロックしていない場合や、要素のレンダリングを行わない場合でも、LCP が遅延する可能性があります。

最もよくある理由は、ページでサイズの大きな JavaScript ファイルを読み込む際に、ブラウザがメインスレッドでコードを解析して実行するのに時間がかかることです。つまり、LCP リソースが完全にダウンロードされた場合でも、無関係なスクリプトの実行が完了するまでレンダリングを待機しなければならない場合があります。

すべてのブラウザはメインスレッドで画像をレンダリングします。つまり、メインスレッドをブロックしているものがあれば、要素の不要なレンダリング遅延につながる可能性があります。したがって、サイズの大きい JavaScript ファイルを、必要に応じて解析できる複数のスクリプト ファイルに分割することをおすすめします。

リソースの読み込み時間を短縮する

このステップの目標は、ブラウザがリソースをネットワーク経由でユーザーのデバイスに転送するために費やす時間を短縮することです。一般的に、これを行う方法はいくつかあります。

  • リソースのサイズを小さくします。
  • リソースの移動距離を短くします。
  • ネットワーク帯域幅の競合を軽減する。
  • ネットワーク時間を完全に排除する

リソースのサイズを縮小する

LCP リソースは通常、画像やウェブフォントです。両方のサイズを縮小する方法については、次のガイドをご覧ください。

リソースの移動距離を短縮する

サーバーを地理的に可能な限りユーザーの近くに配置することで、読み込み時間を減らすこともできます。そのための最適な方法は、コンテンツ配信ネットワーク(CDN)を使用することです。

実際、画像 CDN は、リソースの移動距離を短縮し、前述の戦略に従ってリソースのサイズを縮小することが多いため、特に便利です。

キーポイント: Image CDN は、リソースの読み込み時間を減らすのに最適な方法です。ただし、サードパーティのドメインを使用してイメージをホストすると、追加の接続コストがかかります。オリジンに事前に接続することでこの費用の一部は軽減できますが、最適なオプションは、HTML ドキュメントと同じオリジンから画像を提供することです。これを可能にするために、多くの CDN では送信元から送信元にリクエストをプロキシできます。

ネットワーク帯域幅の競合を減らす

ページで同時に多数のリソースを読み込むと、1 つのリソースの読み込みに時間がかかることがあります。この問題はネットワーク競合と呼ばれています。

LCP リソースの fetchpriority高く設定し、できるだけ早く読み込みを開始した場合、ブラウザは優先度の低いリソースと競合しないように最善を尽くします。ただし、一度に読み込むリソースが多すぎると、特にリソースの多くで fetchpriority が高い場合は、LCP に影響する可能性があります。fetchpriority の値が大きいリソースのみを、最も迅速に読み込む必要があるリソースのみにすることで、ネットワーク競合を減らすことをおすすめします。

ネットワーク時間を完全になくす

リソースの読み込み時間を短縮する最善の方法は、プロセスからネットワークを完全に除外することです。効率的なキャッシュ制御ポリシーを使用してリソースを提供する場合、ユーザーがそのリソースを再度リクエストすると、キャッシュからリソースが提供されます。これにより、リソースの読み込み時間が実質的にゼロになります。

LCP リソースがウェブフォントの場合は、ウェブフォントサイズを縮小するだけでなく、ウェブフォント リソースの読み込み時にレンダリングをブロックする必要があるかどうかを検討することをおすすめします。font-display の値を auto または block 以外に設定すると、テキストは読み込み中に常に表示されるため、LCP は追加のネットワーク リクエストを待つ必要はありません。

最後に、LCP リソースが小さい場合は、追加のネットワーク リクエストを避けるために、リソースをデータ URI としてインライン化すると合理的です。ただし、データ URI の使用にはデメリットがあります。リソースがキャッシュに保存されず、追加のデコードコストのためにレンダリングの遅延が長くなる可能性があります。

4. 最初のバイトまでの時間の短縮

このステップの目的は、最初の HTML をできるだけ早く配信することです。このステップは、通常、デベロッパーが最も制御できないものであるため、最後に記載されています。ただし、後続のすべてのステップに直接影響するため、最も重要なステップでもあります。バックエンドがその最初のバイトのコンテンツを配信するまで、フロントエンドでは何も起こりません。したがって、TTFB を高速化するためにできることは、他のすべての負荷指標も改善します。

高速のサイトで TTFB が遅延する一般的な原因は、広告や短縮リンクなど、複数のリダイレクト経由でユーザーがアクセスしていることです。訪問者が待つ必要があるリダイレクトの数は常に最小限に抑えてください。

もう 1 つのよくある原因は、キャッシュに保存されたコンテンツを CDN エッジサーバーから使用できず、すべてのリクエストを送信元サーバーに転送しなければならないことです。これは、分析用にユーザーが固有の URL パラメータを使用している場合に、表示されるページが異なる場合でも発生することがあります。

TTFB を短縮するための具体的なガイダンスについては、TTFB を最適化するをご覧ください。

JavaScript で LCP の内訳をモニタリングする

すべての LCP サブカテゴリの時間情報は、次のパフォーマンス API を組み合わせて JavaScript で参照できます。

こうしたタイミングの値を JavaScript で計算すると、分析プロバイダに送信したり、デベロッパー ツールに記録したりして、デバッグと最適化に役立てることができます。たとえば、次のスクリーンショットでは、User Timing APIperformance.measure() メソッドを使用して、Chrome DevTools の [Performance] パネルの [Timings] トラックにバーを追加しています。

Chrome DevTools に表示される LCP サブカテゴリのカスタム速度の測定値
速度トラックには、LCP サブカテゴリのタイムラインが表示されます。

速度トラックの可視化は、ネットワーク トラックとメインスレッド トラックとともに特に役立ちます。これらのトラックでは、これらの期間中にページで他に何が起こっているかを確認できます。

JavaScript を使用して各サブカテゴリの合計 LCP 時間の何パーセントを占めるかを計算し、ページが推奨される割合の内訳を満たしているかどうかを判断することもできます。

このスクリーンショットは、各 LCP サブカテゴリの合計時間と、合計 LCP 時間の割合をコンソールに記録する例を示しています。

LCP サブカテゴリの時間と、その LCP の割合(コンソールに出力されます)
LCP サブカテゴリのタイミングと割合

これらのビジュアリゼーションは、どちらも次のコードを使用して作成されました。

const LCP_SUB_PARTS = [
  'Time to first byte',
  'Resource load delay',
  'Resource load time',
  'Element render delay',
];

new PerformanceObserver((list) => {
  const lcpEntry = list.getEntries().at(-1);
  const navEntry = performance.getEntriesByType('navigation')[0];
  const lcpResEntry = performance
    .getEntriesByType('resource')
    .filter((e) => e.name === lcpEntry.url)[0];

  // Ignore LCP entries that aren't images to reduce DevTools noise.
  // Comment this line out if you want to include text entries.
  if (!lcpEntry.url) return;

  // Compute the start and end times of each LCP sub-part.
  // WARNING! If your LCP resource is loaded cross-origin, make sure to add
  // the `Timing-Allow-Origin` (TAO) header to get the most accurate results.
  const ttfb = navEntry.responseStart;
  const lcpRequestStart = Math.max(
    ttfb,
    // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
    lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0
  );
  const lcpResponseEnd = Math.max(
    lcpRequestStart,
    lcpResEntry ? lcpResEntry.responseEnd : 0
  );
  const lcpRenderTime = Math.max(
    lcpResponseEnd,
    // Use LCP startTime (the final LCP time) because there are sometimes
    // slight differences between loadTime/renderTime and startTime
    // due to rounding precision.
    lcpEntry ? lcpEntry.startTime : 0
  );

  // Clear previous measures before making new ones.
  // Note: due to a bug, this doesn't work in Chrome DevTools.
  LCP_SUB_PARTS.forEach((part) => performance.clearMeasures(part));

  // Create measures for each LCP sub-part for easier
  // visualization in the Chrome DevTools Performance panel.
  const lcpSubPartMeasures = [
    performance.measure(LCP_SUB_PARTS[0], {
      start: 0,
      end: ttfb,
    }),
    performance.measure(LCP_SUB_PARTS[1], {
      start: ttfb,
      end: lcpRequestStart,
    }),
    performance.measure(LCP_SUB_PARTS[2], {
      start: lcpRequestStart,
      end: lcpResponseEnd,
    }),
    performance.measure(LCP_SUB_PARTS[3], {
      start: lcpResponseEnd,
      end: lcpRenderTime,
    }),
  ];

  // Log helpful debug information to the console.
  console.log('LCP value: ', lcpRenderTime);
  console.log('LCP element: ', lcpEntry.element, lcpEntry.url);
  console.table(
    lcpSubPartMeasures.map((measure) => ({
      'LCP sub-part': measure.name,
      'Time (ms)': measure.duration,
      '% of LCP': `${
        Math.round((1000 * measure.duration) / lcpRenderTime) / 10
      }%`,
    }))
  );
}).observe({type: 'largest-contentful-paint', buffered: true});

ローカル デバッグでは、このコードをそのまま使用することも、このデータを分析プロバイダに送信するように変更することもできます。これにより、実際のユーザーに対するページの LCP の内訳をより的確に把握できます。

Web Vitals 拡張機能を使用して LCP の内訳をモニタリングする

Web Vitals 拡張機能は、LCP 時間、LCP 要素、コンソール ロギングの 4 つのサブカテゴリを記録して、この内訳を表示します。

LCP のサブパートのタイミングを示す Web Vitals 拡張機能のコンソール ロギングのスクリーンショット
Web Vitals 拡張機能の [コンソール] パネルに、LCP の内訳が表示されます。