Largest Contentful Paint を最適化する

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

公開日: 2020 年 4 月 30 日

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

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

<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 データを利用できる場合は、必ずまず実際のユーザーデータに集中してください。

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

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

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

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

PageSpeed Insight が URL レベルのデータを利用できないオリジンレベルのデータにフォールバックする
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 に関連する監査のみを次のように表示できます。

Lighthouse LCP の機会と診断
Lighthouse の診断と LCP 改善の提案。

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

Lighthouse の LCP フェーズ
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 要素ではレンダリングのために画像リクエストが必要です。

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 つには「遅延」という言葉が含まれています。あります。これが、これらの時間をできる限り 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 リソースの読み込みが最初のリソースより遅い場合は、改善の余地があります。

最初のリソースの後に開始される 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">
<ph type="x-smartling-placeholder">

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

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. リソースの読み込み時間を短縮する

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

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

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

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

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

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

特に Image 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 の [パフォーマンス] パネルのタイミング トラックにバーを追加しています。

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

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

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

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

コンソールに出力される LCP サブカテゴリの時間と LCP の割合
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 の内訳をより詳しく把握することもできます。

Chrome DevTools を使用して LCP の内訳をモニタリングする

Chrome DevTools で、LCP 時間、LCP 要素、これら 4 つのサブパートがリアルタイムでログに記録されるため、この内訳を確認できます。

Chrome DevTools の [Performance] パネルの LCP サブパートのタイミング
Chrome DevTools の [パフォーマンス] パネルの LCP サブパートのタイミング。

概要

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

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

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

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