Largest Contentful Paint を最適化する

LCP を掘り下げて、改善の余地がある領域を特定する方法を解説します。

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

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

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"></ph> 良好な LCP 値は 2.5 秒以下、低値は 4.0 秒を超えており、その中間には改善が必要です。
良好な LCP 値は 2.5 秒以下です。

ブラウザがウェブページを読み込んでレンダリングする速度には、さまざまな要因が影響し、それらの遅延が LCP に大きな影響を与える可能性があります。

ページの特定の部分をすぐに修正するだけで、LCP が有意に改善されることはめったにありません。LCP を改善するには、読み込みプロセス全体を見直し、そのすべてのステップを最適化する必要があります。

LCP 指標について

LCP を最適化する前に、LCP の問題が発生しているかどうか、また問題の範囲を把握する必要があります。

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

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

PageSpeed Insights の CrUX LCP データを使用する

PageSpeed Insights を使用すると、上部の [実際のユーザーの状況を確認する] というセクションから CrUX データにアクセスできます。ラボベースのより詳細なデータは、下部のパフォーマンスの問題を診断するというセクションで確認できます。ウェブサイトで CrUX データを利用できる場合は、必ずまず実際のユーザーデータに集中してください。

<ph type="x-smartling-placeholder">
</ph> PageSpeed Insights に表示される CrUX データ <ph type="x-smartling-placeholder">
</ph> PageSpeed Insights に表示される CrUX データ。
で確認できます。
<ph type="x-smartling-placeholder">

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

  • この URLモバイルデータ
  • [この URL] のパソコンデータ
  • Origin 全体のモバイルデータ
  • Origin 全体の Desktop データ

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

<ph type="x-smartling-placeholder">
</ph> PageSpeed Insight が URL レベルのデータを利用できないオリジンレベルのデータにフォールバックする <ph type="x-smartling-placeholder">
</ph> PageSpeed Insights に URL レベルのデータがない場合、 オリジンレベルのデータ。

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

CrUX データの 4 つのカテゴリを確認すると、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 に関連する監査のみを表示できます。

<ph type="x-smartling-placeholder">
</ph> Lighthouse LCP の機会と診断 <ph type="x-smartling-placeholder">
</ph> Lighthouse の診断結果と LCP を改善するための提案。

[最適化案] の他に、問題の診断に役立つ [診断] 情報も表示されます。Largest Contentful Paint 要素診断には、LCP を構成するさまざまなタイミングの内訳が表示されます。

<ph type="x-smartling-placeholder">
</ph> Lighthouse の LCP フェーズ <ph type="x-smartling-placeholder">
</ph> Lighthouse の LCP 要素の内訳。

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

LCP の内訳

LCP を最適化する作業は、PageSpeed Insights で指標の改善方法が得られない場合、より複雑な作業になることがあります。一般に、複雑なタスクの場合は、それを小さく、扱いやすいタスクに分割し、個別に対処することをおすすめします。

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

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

  1. 最初の HTML ドキュメント
  2. LCP リソース(該当する場合)

そのページの他のリクエストが LCP に影響する可能性がありますが、この 2 つのリクエスト(具体的には、LCP リソースの開始時と終了時)を見ると、ページが LCP 向けに最適化されているかどうかを確認できます。

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

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

<ph type="x-smartling-placeholder">
</ph> HTML リソースと LCP リソースがハイライト表示されたネットワーク ウォーターフォール <ph type="x-smartling-placeholder">
</ph> 読み込み時間を示すウォーターフォール図 LCP に必要なリソースが含まれます。

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

Time to First Byte(TTFB)
ユーザーがページの読み込みを開始してからブラウザが開くまでの時間 HTML ドキュメントのレスポンスの最初のバイトを受信する。
リソース読み込みの遅延
TTFB からブラウザが LCP リソースの読み込みを開始するまでの時間。条件 LCP 要素のレンダリングにリソースの読み込みは必要ありません(たとえば、 要素がシステム フォントでレンダリングされたテキストノードの場合、今回は 0 になります。
リソースの読み込み時間
LCP リソース自体の読み込みにかかる時間。LCP の 要素のレンダリングにリソースの読み込みは必要ありません。今回は 0 です。
要素のレンダリングの遅延
LCP リソースの読み込みが完了してから LCP 要素が表示されるまでの時間 完全にレンダリングされます。

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

<ph type="x-smartling-placeholder">
</ph> 4 つのサブカテゴリを示す LCP の内訳 <ph type="x-smartling-placeholder">
</ph> 同じウォーターフォールの図。4 つの LCP サブカテゴリが重なっている タイムライン上にあります。

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

LCP を最適化する場合は、これらのサブ要素を個別に最適化することをおすすめします。ただし、そのすべてを最適化する必要があることにも留意することが重要です。場合によっては、ある部分に適用した最適化を行っても LCP は改善されず、短縮された時間が別の部分に移るだけです。

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

<ph type="x-smartling-placeholder">
</ph> 先ほど示した LCP の内訳と同じく、リソース読み込み時間のサブカテゴリが短縮されていますが、全体の LCP 時間は変わりません。 <ph type="x-smartling-placeholder">
</ph> リソースの読み込み時間を短くすると、LCP は減少せず、要素のレンダリングの遅延が増加します。

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

この例は、LCP の最良の結果を得るために、これらのサブパートすべてを最適化する必要があるポイントを示しています。

最適なサブパート時間

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

4 つのサブパートのうち、2 つには「遅延」という言葉が含まれています。あります。これが、これらの時間を可能な限り 0 に近づけるための手がかりになります。他の 2 つの部分にはネットワーク リクエストが関係しますが、その性質上、時間がかかります。

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

これらの時間の内訳はガイドラインであり、厳格なルールではありません。ページの LCP 時間が一貫して 2.5 秒以内である場合、相対的な割合はそれほど重要ではありません。ただし、どちらかの「遅延」期間で不要な時間が長くなると、2.5 秒の目標を絶えず達成することが非常に困難になります。

LCP の時間の内訳について考えると、以下のようになります。

  • LCP 時間の大半を HTML ドキュメントと LCP ソースの読み込みに費やしてください。
  • LCP の導入前、これら 2 つのリソースのいずれかが読み込まれていない場合は、いつでも改善の余地が生じます。
で確認できます。 <ph type="x-smartling-placeholder">

各要素を最適化する方法

LCP の各サブパート タイムを、適切に最適化されたページでどのように分類すればよいかがわかったところで、次は自分のページの最適化に取り掛かりましょう。

次の 4 つのセクションでは、各要素を最適化するための推奨事項とベスト プラクティスを紹介します。リストには、影響が最も大きいと思われる最適化から順に表示されます。

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

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

原則として、LCP リソースの読み込みは、そのページで最初に読み込まれたリソースと同時に開始する必要があります。言い換えると、LCP リソースの読み込みが最初のリソースよりも遅れて開始された場合は、改善の余地があります。

<ph type="x-smartling-placeholder">
</ph> LCP リソースが最初のリソースの後に開始され、改善の機会があることを示すネットワーク ウォーターフォールの図 <ph type="x-smartling-placeholder">
</ph> このページで、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 属性(多くの場合 data-src または data-srcset)を非表示にする JavaScript ライブラリによる遅延読み込みを行います。
  • 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">
<ph type="x-smartling-placeholder">

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

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

たとえば、<img> 要素で loading="lazy" を設定すると、HTML を使用して LCP 画像を遅延できます。遅延読み込みを使用すると、画像がビューポートにあることがレイアウトによって確認されるまでリソースが読み込まれないため、読み込みが本来よりも遅く開始される可能性があります。

<ph type="x-smartling-placeholder">

遅延読み込みを行わなくても、画像はレンダリングをブロックするリソースではないため、ブラウザによって最初に最優先で読み込まれることはありません。優先度の高いリソースに 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 リソースは最初のリソースと同時に開始されます)。

<ph type="x-smartling-placeholder">
</ph> LCP リソースが最初のリソースと同時に開始されることを示すネットワーク ウォーターフォールの図 <ph type="x-smartling-placeholder">
</ph> スタイルシートと同時に LCP リソースの読み込みが開始されました。
で確認できます。
<ph type="x-smartling-placeholder">

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

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

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

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

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

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

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

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

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

  • 追加のネットワーク リクエストを回避するために、スタイルシートを 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. リソースの読み込み時間を短縮する

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

  • リソースのサイズを小さくします。
  • リソースの移動距離を短くする。
  • ネットワーク帯域幅の競合を減らす。
  • ネットワーク時間をまったく使用しない

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

ページに LCP リソースがある場合は、画像またはウェブフォントになります。次のガイドでは、両方のサイズを小さくする方法について詳しく説明しています。

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

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

特に Image CDN は、リソースの移動距離を短くするだけでなく、一般的にリソースのサイズを小さくし、前述のサイズ削減の推奨事項をすべて自動的に実装するため、特に役立ちます。

<ph type="x-smartling-placeholder">

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

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

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

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

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

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] トラックにバーを追加しています。

<ph type="x-smartling-placeholder">
</ph> Chrome DevTools で可視化された LCP サブカテゴリのカスタム速度の測定 <ph type="x-smartling-placeholder">
</ph> 速度のトラックには、LCP サブカテゴリのタイムラインが表示されます。

タイミング トラックのビジュアリゼーションは、ネットワーク トラックとメインスレッド トラックと並んで見たときに特に役立ちます。これらの期間中にページ上の他のものを一目で確認できるためです。

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

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

<ph type="x-smartling-placeholder">
</ph> コンソールに出力される LCP サブカテゴリの時間と LCP の割合 <ph type="x-smartling-placeholder">
</ph> LCP サブカテゴリのタイミングと割合。

これらの可視化はどちらも次のコードを使用して作成されました。

const LCP_SUB_PARTS = [
  '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 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 つのサブパートがコンソールに記録されるため、この内訳を確認できます。

<ph type="x-smartling-placeholder">
</ph> LCP のサブパートのタイミングを示す Web Vitals 拡張機能のコンソール ロギング <ph type="x-smartling-placeholder">
</ph> ウェブの [Console] パネル Vitals 拡張機能に LCP の内訳が表示されます。

概要

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

LCP の最適化は、大きく分けて 4 つのステップで行われます。

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

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