Largest Contentful Paint を最適化する

LCP を分解して改善すべき主な領域を特定する方法に関するステップバイステップ ガイド。

公開日: 2020 年 4 月 30 日

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

優れたユーザー エクスペリエンスを提供するには、ページアクセスの 75% 以上で LCP を 2.5 秒以下に収めるようにします。

良好な LCP 値は 2.5 秒未満、低い値は 4.0 秒を超え、その間の値は改善が必要です
良好な LCP 値は 2.5 秒未満です。

ブラウザがウェブページを読み込み、レンダリングする速度には、さまざまな要因が影響します。これらの要因のいずれかで遅延が発生すると、LCP に大きな影響が及ぶ可能性があります。

ページの一部をその場しのぎで修正しただけで LCP に意義のある改善が見られることは稀です。LCP を改善するには、読み込みプロセス全体を確認し、すべてのステップを最適化する必要があります。

LCP 指標について

LCP を最適化する前に、LCP の問題が存在するかどうか、存在する場合はその問題の程度を把握する必要があります。

LCP はさまざまなツールで測定できますが、これらのツールが LCP を測定する方法はすべて同じではありません。実際のユーザーの LCP を把握するには、Lighthouse などのラボベースのツールやローカル テストの結果ではなく、実際のユーザーがどのように使用しているかを確認する必要があります。これらのラボベースのツールは、LCP の説明や改善に役立つ豊富な情報を提供できますが、ラボテストだけでは実際のユーザー エクスペリエンスを完全に表すものではないことに注意してください。

実際のユーザーに基づく LCP データは、サイトにインストールされたリアルユーザー モニタリング(RUM)ツールから取得できます。また、Chrome ユーザー エクスペリエンス レポート(CrUX)を使用して、数百万ものウェブサイトの実際の Chrome ユーザーから匿名データを収集することもできます。

Chrome DevTools の CrUX LCP データを使用する

Chrome DevTools の [パフォーマンス] ペインでは、リアルタイム指標ビューで、ページまたはオリジンの CrUX LCP の横にローカル LCP エクスペリエンスが表示されます。

Chrome DevTools の [パフォーマンス] パネルのローカル LCP とフィールド LCP
Chrome DevTools の [パフォーマンス] パネルのローカル LCP とフィールド LCP。

フィールド データを [パフォーマンス] パネルに重ねて表示すると、ページに実際のユーザーの LCP に関する問題があるかどうかを評価し、ローカル環境の設定を調整して、問題を再現してデバッグしやすくなります。

PageSpeed Insights CrUX LCP データの使用

PageSpeed Insights の [実際のユーザー エクスペリエンスを確認する] という上部のセクションで、CrUX データにアクセスできます。より詳細なラボベースのデータは、下部にある [パフォーマンスの問題を診断する] セクションで確認できます。ウェブサイトで CrUX データを利用できる場合は、常に実際のユーザーデータに重点を置いてください。

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

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

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

これらの設定は、このセクションの上部と右上にあるコントロールで切り替えることができます。URL レベルで表示するのに十分なデータが URL にない場合でも、オリジンのデータがある場合は、PageSpeed Insights には常にオリジンのデータが表示されます。

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

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

4 つの異なるカテゴリの CrUX データを確認すると、LCP の問題がこのページに固有のものなのか、サイト全体に共通するものなのかを把握できます。同様に、LCP の問題が発生しているデバイスタイプを確認することもできます。

PageSpeed Insights CrUX 補足指標を使用する

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 リソースタイプとサブパートは、CrUX でも利用できます

次に、これらのサブパートについて詳しく説明します。

LCP の内訳

PageSpeed Insights でこの指標を改善する方法が示されていない場合、LCP の最適化はより複雑なタスクになる可能性があります。複雑なタスクの場合は、通常、扱いやすい小さなタスクに分割し、それぞれを個別に対処することをおすすめします。

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

通常、ほとんどのページ読み込みには複数のネットワーク リクエストが含まれますが、LCP の改善の機会を特定するには、まず次の 2 つを確認する必要があります。

  1. 最初の HTML ドキュメント
  2. 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 つのサブカテゴリで構成されます。これらの時間の間にギャップや重複はなく、合計すると LCP の合計時間になります。

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

すべてのページの LCP 値は、これらの 4 つのサブパートに分割できます。重複やギャップはありません。これらを合計すると、LCP の合計時間になります。

LCP を最適化する際は、これらのサブパートを個別に最適化することをおすすめします。ただし、これらはすべて最適化する必要があります。一部に適用した最適化によって LCP が改善されず、節約した時間が別の部分にシフトされることもあります。

たとえば、前述のネットワーク ウォーターフォールで、画像の圧縮を強化するか、より最適な形式(AVIF や WebP など)に切り替えて画像のファイルサイズを小さくすると、リソースの読み込み時間は短縮されますが、時間は要素のレンダリング遅延のサブパートにシフトされるため、LCP は実際には改善されません。

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

これは、このページでは JavaScript コードの読み込みが完了するまで LCP 要素が非表示になり、読み込みが完了するとすべてが一度に表示されるからです。

この例は、LCP の成果を最大化するには、これらのサブパートをすべて最適化する必要があることを示しています。

最適なサブパート時間

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

4 つのサブパートのうち、2 つの名前に「delay」という単語が含まれています。つまり、これらの時間をできるだけゼロに近づけることが重要です。残りの 2 つの部分はネットワーク リクエストを伴うため、時間がかかります。

LCP サブパート LCP の割合
Time to First Byte 約 40%
リソース読み込みの遅延 10% 未満
リソースの読み込み時間 約 40%
要素のレンダリングの遅延 10% 未満
合計 100%

これらの時間の分類はガイドラインであり、厳格なルールではありません。ページの LCP 時間が常に 2.5 秒以内であれば、相対的な割合は重要ではありません。ただし、どちらかの「遅延」部分で不要な時間を費やしていると、2.5 秒の目標を常に達成することは非常に困難です。

LCP 時間の内訳を把握する方法は次のとおりです。

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

各部分を最適化する方法

適切に最適化されたページで LCP の各サブパートの時間がどのように分割されるかを理解できたので、次は自分のページの最適化を始めましょう。

以降の 4 つのセクションでは、各部分を最適化する方法に関する推奨事項とベスト プラクティスについて説明します。影響が最も大きい最適化案から順に表示されます。

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

このステップの目的は、LCP リソースの読み込みをできるだけ早く開始することです。理論上、リソースの読み込みを開始できる最短時間は TTFB の直後ですが、実際にブラウザがリソースの読み込みを開始するまでに常に遅延が発生します。

目安としては、LCP リソースは、そのページで読み込まれる最初のリソースと同じタイミングで読み込みを開始する必要があります。言い換えれば、LCP リソースの読み込みが最初のリソースより遅い場合は、改善の余地があります。

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

一般的に、LCP リソースの読み込み速度に影響する要因は 2 つあります。

  • リソースが検出された日時。
  • リソースに割り当てられた優先度。

リソースが検出されたときに最適化する

LCP リソースの読み込みをできるだけ早く開始するには、ブラウザのプリロード スキャナが最初の HTML ドキュメント レスポンスでリソースを検出できるようにすることが重要です。たとえば、次の場合に、ブラウザは HTML ドキュメント レスポンスをスキャンして LCP リソースを検出できます。

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

HTML ドキュメント レスポンスのスキャンから LCP リソースを検出できない例をいくつか示します。

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

いずれの場合も、ブラウザはスクリプトを実行するか、スタイルシートを適用する必要があります。通常、ネットワーク リクエストの完了を待つ必要があります。その後、LCP リソースを検出して読み込みを開始できます。これは最適な方法ではありません。

不要なリソース読み込みの遅延を回避するには、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 リソースがスタイルシートと同時に読み込まれるようになりました。

2. 要素のレンダリングの遅延を解消

このステップの目標は、リソースの読み込みが完了した後、いつでも LCP 要素をすぐにレンダリングできるようにすることです。

リソースの読み込みが完了した直後に LCP 要素がレンダリングされない主な理由は、なんらかの理由でレンダリングがブロックされている場合です。

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

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

レンダリングを妨げるスタイルシートを減らすか、インライン化する

HTML マークアップから読み込まれたスタイルシートは、それ以降のすべてのコンテンツのレンダリングをブロックします。これは、通常、スタイル設定されていない HTML をレンダリングしたくないため、適切な動作です。ただし、スタイルシートが非常に大きく、LCP リソースよりも読み込みにかなり時間がかかる場合は、リソースの読み込みが完了した後でも、LCP 要素がレンダリングされなくなります。次の例をご覧ください。

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

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

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

通常、スタイルシートをインライン化する場合は、スタイルシートが小さい場合にのみおすすめします。HTML にインライン化されたコンテンツは、後続のページ読み込みでキャッシュを利用できないためです。スタイルシートが非常に大きく、LCP リソースよりも読み込みに時間がかかる場合は、インライン化に適していない可能性があります。

ほとんどの場合、スタイルシートが LCP 要素のレンダリングをブロックしないようにするには、LCP リソースよりも小さくなるようにサイズを小さくすることをおすすめします。これにより、ほとんどのアクセスでボトルネックにならないようにします。

スタイルシートのサイズを小さくするための推奨事項は次のとおりです。

レンダリングを妨げる JavaScript を遅らせるまたはインライン化する

ページの <head> に同期スクリプト(async 属性または defer 属性のないスクリプト)を追加する必要はほとんどありません。追加すると、ほとんどの場合パフォーマンスに悪影響を与えます。

JavaScript コードをページの読み込みでできるだけ早く実行する必要がある場合は、別のネットワーク リクエストを待機してレンダリングが遅れないように、コードをインライン化することをおすすめします。ただし、スタイルシートと同様に、スクリプトが非常に小さい場合にのみ、スクリプトをインライン化する必要があります。

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

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

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

LCP の最適化という観点から、SSR には主に次の 2 つの利点があります。

  • 画像リソースは HTML ソースから検出可能になります(前述のステップ 1 を参照)。
  • ページ コンテンツのレンダリングを完了するために、追加の JavaScript リクエストを待つ必要はありません。

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

SSR に似たオプションとして、静的サイト生成(SSG)または事前レンダリングがあります。これは、オンデマンドではなくビルドステップで HTML ページを生成するプロセスです。アーキテクチャでプリレンダリングが可能な場合は、通常、パフォーマンスの観点からプリレンダリングを選択することをおすすめします。

長いタスクを分割する

前述のアドバイスに沿って、JavaScript コードがレンダリング ブロックでもなく、要素のレンダリングの責任も負っていない場合でも、LCP が遅れることがあります。

これが起こる最も一般的な原因は、ページが大きな JavaScript ファイルを読み込み、ブラウザのメインスレッドで解析して実行する必要がある場合です。つまり、画像リソースが完全にダウンロードされた場合でも、関連のないスクリプトの実行が完了するまで待機してからレンダリングを開始しなければならない場合があります。

現在のすべてのブラウザはメインスレッドで画像をレンダリングします。つまり、メインスレッドをブロックする要素があると、不要な要素のレンダリング遅延が発生する可能性があります。

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

このステップの目的は、ネットワーク経由でユーザーのデバイスにリソースのバイト数を転送する時間を短縮することです。一般に、次の 4 つの方法があります。

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

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

ページの LCP リソース(存在する場合)は、画像またはウェブフォントです。以下のガイドでは、両方のサイズを削減する方法について詳しく説明しています。

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

リソースのサイズを小さくするだけでなく、サーバーをユーザーの地理的位置にできるだけ近づけることで、読み込み時間を短縮することもできます。そのためには、コンテンツ配信ネットワーク(CDN)を使用するのが最善の方法です。

特に画像 CDN は、リソースの移動距離を短縮するだけでなく、通常はリソースのサイズも削減するため、前述のサイズ削減に関する推奨事項をすべて自動的に実装できるため、特に役立ちます。

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

リソースのサイズと移動距離を短縮しても、他の多くのリソースを同時に読み込む場合は、リソースの読み込みに時間がかかることがあります。この問題はネットワーク競合と呼ばれます。

LCP リソースに高い fetchpriority を指定して、できるだけ早く読み込みを開始すると、優先度の低いリソースが競合しないようにブラウザが最善を尽くします。ただし、fetchpriority が高いリソースを多数読み込む場合や、一般に多くのリソースを読み込む場合は、LCP リソースの読み込み速度に影響する可能性があります。

ネットワーク時間を完全に排除する

リソースの読み込み時間を短縮する最善の方法は、プロセスからネットワークを完全に排除することです。効率的なキャッシュ制御ポリシーを使用してリソースを配信すると、リソースを 2 回目にリクエストした訪問者にはキャッシュからリソースが配信されるため、リソースの読み込み時間が実質的にゼロになります。

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

最後に、LCP リソースが小さい場合は、リソースをデータ URL としてインライン化することをおすすめします。これにより、追加のネットワーク リクエストも発生しなくなります。ただし、データ URL を使用する場合は注意が必要です。リソースをキャッシュに保存できないため、デコード費用が増加し、レンダリングの遅延が長引く場合があります。

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

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

サイトの速度は速いのに TTFB が遅い場合、一般的な原因として、広告や短縮リンクなど、複数のリダイレクトを経由してユーザーがアクセスしていることがあります。訪問者が待機しなければならないリダイレクトの数は常に最小限に抑えます。

別の一般的な原因は、キャッシュに保存されたコンテンツを CDN エッジサーバーから使用できず、すべてのリクエストを送信元サーバーに転送する必要がある場合です。これは、訪問者がアナリティクス用に一意の URL パラメータを使用している場合に発生することがあります(ページが異なる場合でも発生することがあります)。

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

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

前述の LCP サブパートのタイミング情報はすべて、次のパフォーマンス API を組み合わせて JavaScript で取得できます。

これらのタイミング値を JavaScript で計算するメリットは、分析プロバイダに送信したり、デベロッパー ツールにログに記録したりして、デバッグと最適化に役立てられることです。

たとえば、次のスクリーンショットは、User Timing APIperformance.measure() メソッドを使用して、Chrome DevTools の [Performance] パネルの [Timings] トラックにバーを追加しています。

Chrome DevTools で可視化された LCP サブカテゴリのユーザー タイミング測定値
タイミング トラックには、LCP サブカテゴリのタイムラインが表示されます。

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

タイミング トラックで LCP のサブパートを可視化するだけでなく、JavaScript を使用して、各サブパートが LCP の合計時間に占める割合を計算することもできます。この情報に基づいて、前述の推奨される割合の分類をページが満たしているかどうかを判断できます。

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

LCP サブカテゴリの時間と、LCP の割合がコンソールに出力される
LCP サブカテゴリのタイミングと割合。

これらの可視化はどちらも、次のコードで作成されています。

const LCP_SUBPARTS = [
  'Time to first byte',
  'Resource load delay',
  'Resource load duration',
  '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 subpart.
  // 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_SUBPARTS.forEach((part) => performance.clearMeasures(part));

  // Create measures for each LCP subpart for easier
  // visualization in the Chrome DevTools Performance panel.
  const lcpSubpartMeasures = [
    performance.measure(LCP_SUBPARTS[0], {
      start: 0,
      end: ttfb,
    }),
    performance.measure(LCP_SUBPARTS[1], {
      start: ttfb,
      end: lcpRequestStart,
    }),
    performance.measure(LCP_SUBPARTS[2], {
      start: lcpRequestStart,
      end: lcpResponseEnd,
    }),
    performance.measure(LCP_SUBPARTS[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 subpart': measure.name,
      'Time (ms)': measure.duration,
      '% of LCP': `${
        Math.round((1000 * measure.duration) / lcpRenderTime) / 10
      }%`,
    }))
  );
}).observe({type: 'largest-contentful-paint', buffered: true});

このコードをそのままローカル デバッグに使用することも、このデータをアナリティクス プロバイダに送信するように変更して、実際のユーザーのページでの LCP の内訳を詳しく把握することもできます。

概要

LCP は複雑な指標であり、タイミングはさまざまな要因の影響を受ける可能性があります。ただし、LCP の最適化は主に LCP リソースの負荷の最適化であると考えると、大幅に簡素化できます。

LCP の最適化は、大まかに次の 4 つのステップに分けられます。

  1. LCP リソースの読み込みができる限り早く開始されるようにします。
  2. LCP 要素がリソースの読み込みが完了するとすぐにレンダリングされるようにします。
  3. 品質を損なうことなく、LCP リソースの読み込み時間をできるだけ短縮します。
  4. 最初の HTML ドキュメントをできるだけ早く提供します。

ページでこれらの手順を実施できたら、ユーザーに最適な読み込みエクスペリエンスを提供できていると確信できます。そのことは、実際の LCP スコアに反映されます。