Largest Contentful Paint(LCP)

対応ブラウザ

  • 77
  • 79
  • 122
  • x

ソース

従来、ウェブ デベロッパーにとって、ウェブページのメイン コンテンツの読み込みとユーザーへの表示速度を測定することは困難でした。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 についてレポートされる要素のサイズは通常、ビューポート内でユーザーに表示されるサイズです。要素がビューポートの外に伸びている場合や、クリップされている要素や非表示のオーバーフローoverflowがある場合、これらの部分は要素のサイズにカウントされません。

固有のサイズからサイズ変更された画像要素の場合、表示されるサイズは、表示サイズまたは固有のサイズのいずれか小さい方になります。

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

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

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

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

このような変更の可能性に対処するため、ブラウザは最初のフレームをペイントするとすぐに、最も大きなコンテンツ要素を識別する largest-contentful-paint 型の PerformanceEntry をディスパッチします。ただし、後続のフレームをレンダリングした後、最も大きなコンテンツ要素が変更されるたびに、別の PerformanceEntry がディスパッチされます。

たとえば、テキストとヒーロー画像を含むページでは、ブラウザは最初にテキストをレンダリングし、その時点でブラウザは element プロパティが <p> または <h1> を参照する可能性が高い largest-contentful-paint エントリをディスパッチします。その後、ヒーロー画像の読み込みが完了すると、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 時間に対応しているため、LCP は activationStart から測定する必要があります。

デベロッパーは、こうした微妙な違いをすべて記憶する代わりに、web-vitals JavaScript ライブラリを使用して LCP を測定できます。LCP では、これらの違いを処理できます(可能な場合、iframe の問題は対象外です)。

import {onLCP} from 'web-vitals';

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

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

最大の要素が最も重要ではない場合はどうすればよいでしょうか。

ページ上で最も重要な要素(1 つまたは複数の要素)が最大要素と同じでない場合もあります。その場合は、そのような他の要素のレンダリング時間を測定したいと考えるかもしれません。これは、Element Timing API を使用して行うことができます。詳しくは、カスタム指標についての記事をご覧ください。

LCP を改善する方法

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

参考情報

変更履歴

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

指標の実装または定義に対する変更はすべて、こちらの変更履歴に掲載されています。

これらの指標についてフィードバックがある場合は、web-vitals-feedback Google グループからお寄せください。