Largest Contentful Paint(LCP)は、認識される読み込み速度を測定するための安定した Core Web Vital 指標です。これは、ページ読み込みタイムラインの、ページのメイン コンテンツが読み込まれたと思われる時点を示します。LCP が高速であれば、ユーザーはページが有用であることを保証できます。
従来、ウェブ デベロッパーにとって、ウェブページのメイン コンテンツの読み込みとユーザーへの表示速度を測定することは困難でした。load や DOMContentLoaded などの古い指標は、必ずしもユーザーが画面に表示される内容に対応しているとは限らないため、適切に機能しません。また、First Contentful Paint(FCP)などの新しいユーザー中心のパフォーマンス指標は、読み込みエクスペリエンスの初期段階しかキャプチャしません。ページにスプラッシュ画面や読み込みインジケーターが表示される場合、このタイミングはユーザーとはあまり関係ありません。
これまでは、最初のペイント後の読み込みエクスペリエンスをより正確に把握できるように、First Meaningful Paint(FMP)や Speed Index(SI)(どちらも Lighthouse で利用可能)などのパフォーマンス指標を推奨していましたが、これらの指標は複雑で説明が難しく、間違いが多く、ページのメイン コンテンツがいつ読み込まれたかを識別できません。
W3C ウェブ パフォーマンス ワーキング グループでの議論と Google で行われた調査に基づき、ページのメイン コンテンツが読み込まれたタイミングをより正確に測定するには、最大の要素がレンダリングされたタイミングを確認することがより正確なことがわかりました。
LCP とは
LCP は、ビューポートに表示される最も大きな画像またはテキスト ブロックのレンダリング時間を、ユーザーが最初にページに移動したときを基準としてレポートします。
良い LCP スコアとは
優れたユーザー エクスペリエンスを提供するには、サイトの LCP を 2.5 秒以下にする必要があります。ほとんどのユーザーでこの目標値を達成するには、ページ読み込みの 75 パーセンタイルをモバイル デバイスとデスクトップ デバイスでセグメント化して測定するしきい値として適しています。
どのような要素が考慮されますか?
Largest Contentful Paint API で指定されているように、Largest Contentful Paint と見なされる要素のタイプは次のとおりです。
<img>
要素(GIF やアニメーション PNG などのアニメーション コンテンツには最初のフレームの表示時間が使用されます)<svg>
要素内の<image>
要素<video>
要素(ポスター画像の読み込み時間または動画の最初のフレームの表示時間のいずれか早い方)- CSS グラデーションではなく、
url()
関数を使用して背景画像を読み込む要素 - テキストノードやその他のインライン レベルのテキスト要素の子を含むブロックレベル要素。
複雑さを軽減するために、要素をこの限定セットに制限することは意図的なものです。
今後、さらなる研究の実施に応じて、要素(<svg>
の完全なサポートなど)が追加される可能性があります。
LCP 測定では、一部の要素のみを考慮するだけでなく、ヒューリスティックを使用して、ユーザーが「コンテンツがない」と見なす可能性のある特定の要素を除外します。Chromium ベースのブラウザには、次のようなものがあります。
- 不透明度が 0 の要素。ユーザーには表示されません。
- ビューポート全体を覆う要素。多くの場合、背景要素です。
- プレースホルダ画像、またはページの実際のコンテンツを反映していない可能性のある、エントロピーの低いその他の画像。
ブラウザは今後もこれらのヒューリスティックを改善し、最も大きなコンテンツ要素に関するユーザーの期待に応える予定です。
このような「コンテンツフル」ヒューリスティックは、FCP で使用されるものとは異なります。FCP では、LCP の候補に該当しない場合でも、プレースホルダ画像やフル ビューポート画像など、これらの要素の一部を考慮する可能性があります。どちらも名前に「Contentful」を使用していますが、これらの指標の目的は異なります。FCP は任意のコンテンツが画面にペイントされたタイミングを測定するのに対し、LCP はメイン コンテンツがペイントされたタイミングを測定します。
要素のサイズはどのようにして決定されますか?
LCP についてレポートされる要素のサイズは通常、ビューポート内でユーザーに表示されるサイズです。要素がビューポートの外側に延びている場合や、いずれかの要素がクリップされているか、非表示のoverflowがある場合、それらの部分は要素のサイズにカウントされません。
固有のサイズからサイズ変更された画像要素の場合、報告されるサイズは、表示サイズまたは組み込みサイズのいずれか小さい方になります。
テキスト要素の場合、LCP はすべてのテキストノードを含めることができる最小の長方形のみを考慮します。
LCP では、すべての要素について、CSS を使用して適用されるマージン、パディング、境界は考慮されません。
LCP はいつ報告されますか?
ウェブページは段階的に読み込まれることが多いため、ページ内の最大の要素が読み込み中に変化することがあります。
このような変更の可能性に対処するため、ブラウザは最初のフレームをペイントするとすぐに、最大のコンテンツ要素を示す largest-contentful-paint
タイプの PerformanceEntry
をディスパッチします。後続のフレームをレンダリングした後、最もコンテンツの多い要素が変更されるたびに、別の PerformanceEntry
をディスパッチします。
たとえば、テキストとヒーロー画像を含むページでは、ブラウザは最初にテキストのみをレンダリングし、ブラウザは element
プロパティが <p>
または <h1>
を参照する largest-contentful-paint
エントリをディスパッチします。ヒーロー画像の読み込みが完了すると、element
プロパティが <img>
を参照する 2 つ目の largest-contentful-paint
エントリがディスパッチされます。
要素は、レンダリングされてユーザーに表示された後に限り、最もコンテンツの多い要素とみなすことができます。まだ読み込まれていない画像は「レンダリングされた」とは見なされません。フォント ブロック期間にウェブフォントを使用するテキストノードも使用できません。このような場合、小さい要素が最大の Contentful 要素として報告されますが、大きい要素のレンダリングが完了するとすぐに別の PerformanceEntry
が作成されます。
画像やフォントの読み込みが遅いだけでなく、新しいコンテンツが利用可能になったときに、ページでは DOM に新しい要素が追加されることがあります。これらの新しい要素のいずれかが、以前の最大のコンテンツ要素よりも大きい場合は、新しい PerformanceEntry
が作成されます。
最も大きなコンテンツがビューポートから(または DOM からでも)削除された場合でも、それより大きい要素がレンダリングされない限り、最大のコンテンツの要素として残ります。
ユーザーがページを操作する(タップ、スクロール、キー操作など)とブラウザはすぐに新しいエントリの報告を停止します。これは、ユーザー操作によってユーザーに表示される内容が変化することが多いためです(特にスクロールの場合)。
分析を目的として、最近ディスパッチされた PerformanceEntry
のみを分析サービスに報告します。
読み込み時間とレンダリング時間
セキュリティ上の理由から、Timing-Allow-Origin
ヘッダーのないクロスオリジン画像では、画像のレンダリング タイムスタンプは公開されません。代わりに、他の API がすでに公開している読み込み時間のみを使用できます。
これにより、ウェブ API によって LCP が FCP より前であると報告される、一見不可能と思われる状況が生じる可能性があります。これはセキュリティ制限によるもので、実際の状況を表すものではありません。
指標の精度を高めるために、可能であれば Timing-Allow-Origin
ヘッダーを設定することをおすすめします。
要素のレイアウトとサイズ変更はどのように処理されますか?
新しいパフォーマンス エントリの計算とディスパッチのパフォーマンス オーバーヘッドを低く抑えるため、要素のサイズや位置を変更しても新しい LCP 候補が生成されません。要素の初期サイズとビューポート内の位置のみが考慮されます。
つまり、最初に画面外にレンダリングされて画面上で遷移した画像は報告されない場合があります。また、最初にビューポートにレンダリングされた要素がビュー外に押し出された場合でも、その最初のビューポート内サイズがレポートされます。
例
一般的なウェブサイトで Largest Contentful Paint が発生する例を次に示します。
![cnn.com の Largest Contentful Paint タイムライン](https://web.developers.google.cn/static/articles/lcp/image/largest-contentful-paint-fc43128e011aa.png?hl=ja)
![Techcrunch.com の Largest Contentful Paint タイムライン](https://web.developers.google.cn/static/articles/lcp/image/largest-contentful-paint-3713e2f14970a.png?hl=ja)
どちらのタイムラインでも、コンテンツが読み込まれると、最大の要素(緑色でハイライト表示)が変化します。最初の例では、新しいコンテンツが DOM に追加され、最大の要素が変更されています。2 番目の例では、レイアウトが変更され、前に最大だったコンテンツ要素がビューポートから削除されます。
遅延読み込みのコンテンツは、ページにすでに存在しているコンテンツよりも大きくなることがよくありますが、必ずしもそうとは限りません。次の 2 つの例はページが完全に読み込まれる前の LCP を示しています
![instagram.com の Largest Contentful Paint タイムライン](https://web.developers.google.cn/static/articles/lcp/image/largest-contentful-paint-9bc403e812154.png?hl=ja)
![google.com の Largest Contentful Paint タイムライン](https://web.developers.google.cn/static/articles/lcp/image/largest-contentful-paint-6c5554de0eac7.png?hl=ja)
最初の例では、Instagram のロゴは比較的早い段階で読み込まれ、他のコンテンツが追加されても最大の要素のままです。Google 検索結果ページの例で最大の要素は、画像またはロゴの読み込みが完了する前に表示されるテキストの段落です。個々の画像はこの段落よりも小さいため、読み込みプロセス全体で最大の要素であり続けます。
LCP の測定方法
LCP はラボまたは現場で測定でき、次のツールで利用できます。
フィールド ツール
- Chrome ユーザー エクスペリエンス レポート
- PageSpeed Insights
- Search Console(Core Web Vitals レポート)
web-vitals
JavaScript ライブラリ
ラボ用ツール
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 はユーザーが個別のページ訪問として認識するため、このようなケースで測定する必要があります。 - iframe 内の要素は API で考慮されませんが、指標はページのユーザー エクスペリエンスの一部であるため、指標では考慮されます。iframe 内に LCP を使用するページ(埋め込み動画のポスター画像など)では、CrUX と RUM の違いとして表示されます。LCP を適切に測定するには、iframe を含める必要があります。サブフレームは API を使用して、集計のために
largest-contentful-paint
エントリを親フレームに報告できます。 - API がナビゲーションの開始から LCP を測定します。事前レンダリングされたページの場合は、代わりに
activationStart
からの LCP を測定します。これは、ユーザーが体験した 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()
のソースコードをご覧ください。
最大の要素が最も重要ではない場合はどうすればよいでしょうか。
ページ上で最も重要な要素(1 つまたは複数)が最大要素と同じでない場合もあります。その場合は、そのような他の要素のレンダリング時間を測定したいと考えるかもしれません。これは、カスタム指標に関する記事で説明されているように、Element Timing API を使用して可能です。
LCP を改善する方法
LCP の最適化に関する詳細なガイドでは、実際の LCP タイミングを特定し、ラボデータを使用してドリルダウンして最適化する手順を確認できます。
参考情報
変更履歴
指標の測定に使用する API や、指標自体の定義にバグが見つかることもあります。そのため、変更が必要になることがあり、これらの変更は、内部レポートとダッシュボードに改善または回帰として表示されることがあります。
指標の実装または定義に対する変更はすべて、こちらの変更履歴に掲載されています。
これらの指標に関するフィードバックがある場合は、web-vitals-feedback Google グループからお知らせください。