Largest Contentful Paint(LCP)

対応ブラウザ

  • Chrome: 77。
  • Edge: 79.
  • Firefox: 122。
  • Safari: サポートされていません。

ソース

これまで、ウェブページのメイン コンテンツが読み込まれてユーザーに表示されるまでの時間の測定は、ウェブ デベロッパーにとって課題でした。loadDOMContentLoaded などの古い指標は、ユーザーが画面に表示される内容と必ずしも一致しないため、適切ではありません。また、First Contentful Paint(FCP)などの新しいユーザー中心のパフォーマンス指標は、読み込みのごく初期の段階しか捉えません。ページにスプラッシュ画面が表示されている場合や、読み込みインジケーターが表示されている場合、このタイミングはユーザーにとってあまり関連性がありません。

これまで、最初のペイント後の読み込みエクスペリエンスをより多く把握するために、First Meaningful Paint(FMP)Speed Index(SI)(どちらも Lighthouse で利用可能)などのパフォーマンス指標を推奨してきましたが、これらの指標は複雑で説明が難しく、誤りがある場合が多く、ページのメイン コンテンツが読み込まれたタイミングを特定できません。

W3C ウェブ パフォーマンス ワーキング グループでの議論と Google で行われた調査に基づき、ページのメイン コンテンツが読み込まれたタイミングを測定するより正確な方法は、最も大きな要素がレンダリングされたタイミングを確認することであると判断しました。

LCP とは何ですか?

LCP は、ビューポート内に表示される最大の画像、テキスト ブロック、または動画のレンダリング時間を、ユーザーが最初にページに移動したタイミングと比較する形で確認できます。

良好な LCP スコアとは

優れたユーザー エクスペリエンスを提供するには、サイトで Largest Contentful Paint を 2.5 秒以下に収めるようにします。ほとんどのユーザーが閲覧する際に目標値が達成されるよう、モバイル デバイスとデスクトップ デバイスでページ読み込みの75 パーセンタイルを測定することをおすすめします。

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

どのような要素が考慮されますか?

現在 Largest Contentful Paint API で指定されているように、Largest Contentful Paint と見なされる要素のタイプは次のとおりです。

最初はシンプルにするために、要素をこの限定されたセットに制限しています。今後、調査が進むにつれて、<svg> の完全なサポートなど、追加要素が追加される可能性があります。

LCP の測定では、一部の要素のみが考慮されるだけでなく、ヒューリスティクスを使用して、ユーザーが「コンテンツではない」と判断する可能性が高い特定の要素が除外されます。Chromium ベースのブラウザの場合、以下が含まれます。

  • 不透明度が 0 で、ユーザーには表示されない要素
  • ビューポート全体を覆う要素で、コンテンツではなく背景と見なされる可能性が高いもの
  • ページの実際のコンテンツを反映していない可能性が高い、エントロピーの低いプレースホルダ画像やその他の画像

ブラウザは、最大のコンテンツ要素に関するユーザーの期待に沿うように、これらのヒューリスティクスを継続的に改善していく可能性があります。

これらの「コンテンツを含む」ヒューリスティックは、First Contentful Paint(FCP)で使用されるヒューリスティックとは異なる場合があります。FCP では、プレースホルダ画像やビューポート全体の画像など、LCP の候補として不適格な要素も考慮される場合があります。どちらも名前に「contentful」が含まれていますが、これらの指標の目的は異なります。FCP は任意のコンテンツが画面に描画されるタイミングを測定し、LCP はメイン コンテンツが描画されるタイミングを測定するため、LCP はより選択的なものになっています。

要素のサイズはどのように決まります?

LCP で報告される要素のサイズは、通常、ビューポート内でユーザーに表示されるサイズです。要素がビューポートの外側に広がっている場合、または要素の一部が切り捨てられている場合、または表示されないオーバーフローがある場合、それらの部分は要素のサイズにカウントされません。

固有のサイズからサイズ変更された画像要素の場合、報告されるサイズは、表示サイズと固有のサイズのどちらか小さい方です。

テキスト要素の場合、LCP はすべてのテキストノードを含めることができる最小の長方形のみを考慮します。

すべての要素について、LCP では CSS を使用して適用されたマージン、パディング、境界は考慮されません。

LCP はいつ報告されますか?

ウェブページは段階的に読み込まれるため、ページ上の最大の要素が変更される可能性があります。

この変化を処理するため、ブラウザは最初のフレームをペイントするとすぐに、最大のコンテンツ要素を識別する largest-contentful-paint タイプの PerformanceEntry をディスパッチします。ただし、その後のフレームをレンダリングした後、Largest Contentful Element が変更されるたびに、別の PerformanceEntry がディスパッチされます。

たとえば、テキストとヒーロー画像を含むページでは、ブラウザは最初にテキストのみをレンダリングする場合があります。この時点で、ブラウザは largest-contentful-paint エントリをディスパッチします。このエントリの element プロパティは <p> または <h1> を参照する可能性があります。その後、ヘッダー画像の読み込みが完了すると、2 つ目の largest-contentful-paint エントリがディスパッチされ、その element プロパティが <img> を参照します。

要素がコンテンツを含む最大の要素と見なされるのは、レンダリングされてユーザーに表示された場合のみです。まだ読み込まれていない画像は「レンダリング済み」と見なされません。どちらも、フォント ブロック期間中にウェブフォントを使用しているテキストノードではありません。このような場合、小さい要素が最大コンテンツ要素として報告されることがあります。ただし、大きな要素のレンダリングが完了するとすぐに、別の PerformanceEntry が作成されます。

画像やフォントが遅れて読み込まれるだけでなく、新しいコンテンツが利用可能になると、ページが DOM に新しい要素を追加することもあります。これらの新しい要素のいずれかが、以前の最大のコンテンツ要素よりも大きい場合、新しい PerformanceEntry も報告されます。

最大のコンテンツ要素がビューポートから削除された場合や、DOM から削除された場合でも、より大きな要素がレンダリングされない限り、最大のコンテンツ要素のままになります。

ユーザーがページを操作すると(タップ、スクロール、キー操作など)、ブラウザは新しいエントリのレポートを停止します。これは、ユーザーが操作すると、表示内容が変更されることがよくあるからです(特にスクロールの場合)。

分析目的では、直近に送信された PerformanceEntry のみをアナリティクス サービスに報告する必要があります。

読み込み時間とレンダリング時間

セキュリティ上の理由から、Timing-Allow-Origin ヘッダーのないクロスオリジン画像については、画像のレンダリング タイムスタンプが公開されません。代わりに、読み込み時間のみが公開されます(これは他の多くのウェブ API ですでに公開されているためです)。

これにより、ウェブ API によって LCP が FCP より早い時間として報告されるという、ありえないと思われる状況が発生する可能性があります。実際にはそうではありませんが、このセキュリティ制限によりそう見えるだけです。

可能であれば、指標の精度を高めるために、常に Timing-Allow-Origin ヘッダーを設定することをおすすめします。

要素のレイアウトとサイズの変更はどのように処理されますか?

新しいパフォーマンス エントリの計算とディスパッチのパフォーマンス オーバーヘッドを低く抑えるために、要素のサイズや位置を変更しても、新しい LCP 候補は生成されません。要素の初期サイズとビューポート内の位置のみが考慮されます。

つまり、最初に画面外でレンダリングされ、その後画面上に移行する画像は報告されない可能性があります。また、最初にビューポート内でレンダリングされた要素が押し下げられ、ビューポート外になった場合でも、最初のビューポート内のサイズが報告されます。

以下に、一般的なウェブサイトで Largest Contentful Paint が発生するタイミングの例を示します。

cnn.com の Largest Contentful Paint のタイムライン
cnn.com の LCP のタイムライン。
techcrunch.com の Largest Contentful Paint のタイムライン
techcrunch.com の LCP のタイムライン。

上記の両方のタイムラインで、コンテンツの読み込みに伴い最大要素が変化しています。最初の例では、DOM に新しいコンテンツが追加され、最も大きい要素が変更されます。2 つ目の例では、レイアウトが変更され、以前は最大だったコンテンツがビューポートから削除されています。

遅れて読み込まれるコンテンツは、ページにすでに表示されているコンテンツよりも大きいことがよくありますが、必ずしもそうとは限りません。次の 2 つの例は、ページが完全に読み込まれる前に LCP が発生していることを示しています。

instagram.com の Largest Contentful Paint のタイムライン
instagram.com の LCP タイムライン。
google.com の Largest Contentful Paint のタイムライン
google.com の LCP タイムライン。

最初の例では、Instagram のロゴが比較的早い段階で読み込まれ、他のコンテンツが段階的に表示されても最大の要素のままです。Google 検索結果ページの例では、最も大きい要素は、画像やロゴの読み込みが完了する前に表示されるテキストの段落です。個々の画像はすべてこの段落より小さいため、読み込みプロセス全体で最大の要素になります。

LCP を測定する方法

LCP はラボまたは現場で測定できます。次のツールで利用できます。

フィールドツール

ラボツール

JavaScript で LCP を測定する

JavaScript で LCP を測定するには、Largest Contentful Paint API を使用します。次の例は、largest-contentful-paint エントリをリッスンしてコンソールにログに記録する PerformanceObserver を作成する方法を示しています。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime, entry);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});

上記の例では、ログに記録された各 largest-contentful-paint エントリは、現在の LCP 候補を表します。通常、出力された最後のエントリの startTime 値が LCP 値になりますが、必ずしもそうとは限りません。すべての largest-contentful-paint エントリが LCP の測定に有効なわけではありません。

次のセクションでは、API が報告する内容と指標の計算方法の違いについて説明します。

指標と API の違い

  • API は、バックグラウンド タブで読み込まれたページの largest-contentful-paint エントリをディスパッチしますが、LCP の計算ではこれらのページは無視する必要があります。
  • ページがバックグラウンドに移行した後も、API は largest-contentful-paint エントリを送信し続けますが、LCP の計算ではこれらのエントリは無視する必要があります(要素は、ページが常にフォアグラウンドにあった場合にのみ考慮されます)。
  • ページが前後のキャッシュから復元された場合、API は largest-contentful-paint エントリを報告しませんが、ユーザーは個別のページ訪問として認識するため、LCP は測定する必要があります。
  • API は iframe 内の要素を考慮しませんが、指標はページのユーザー エクスペリエンスの一部であるため、iframe 内の要素を考慮します。iframe 内に LCP があるページ(埋め込み動画のポスター画像など)では、CrUX と RUM の差異として表示されます。LCP を適切に測定するには、これらの点を考慮する必要があります。サブフレームは、API を使用して largest-contentful-paint エントリを親フレームに報告し、集計できます。
  • API はナビゲーション開始から LCP を測定しますが、事前レンダリングされたページの場合は、ユーザーが認識する LCP 時間に対応するため、activationStart から LCP を測定する必要があります。

このような微妙な違いをすべて覚えておくのではなく、web-vitals JavaScript ライブラリを使用して LCP を測定すると、これらの違いが自動的に処理されます(可能であれば。iframe の問題は対象外です)。

import {onLCP} from 'web-vitals';

// Measure and log LCP as soon as it's available.
onLCP(console.log);

JavaScript で LCP を測定する方法の完全な例については、onLCP() のソースコードをご覧ください。

最も大きい要素が最も重要でない場合はどうすればよいですか?

ページ上で最も重要な要素(複数可)が最も大きい要素と一致しない場合があります。デベロッパーは、このような他の要素のレンダリング時間を測定することに関心があるかもしれません。これは、カスタム指標の記事で説明されているように、Element Timing API を使用して行うことができます。

LCP を改善する方法

LCP の最適化に関する完全なガイドでは、現場で LCP のタイミングを特定し、ラボデータを使用してドリルダウンして最適化するプロセスについて説明しています。

参考情報

変更履歴

指標の測定に使用される API や、指標自体の定義でバグが見つかることがあります。そのため、変更を加える必要が生じることがあります。これらの変更は、内部レポートやダッシュボードで改善または低下として表示される場合があります。

これらの指標の実装または定義に対するすべての変更は、この変更ログに表示されます。

これらの指標に関するフィードバックがある場合は、web-vitals-feedback Google グループで送信してください。