従来、ウェブ デベロッパーにとって、ウェブページのメイン コンテンツがどれだけ速く読み込まれてユーザーに表示されるかを測定することは困難でした。load や DOMContentLoaded などの古い指標は、ユーザーが画面に表示される内容と必ずしも一致しないため、適切に機能しません。また、First Contentful Paint(FCP)のようなユーザー中心のパフォーマンス指標は、読み込み処理の初期段階にすぎません。ページにスプラッシュ画面や読み込みインジケーターが表示されている場合、そのタイミングはユーザーとあまり関係ありません。
これまでは、初回ペイント後の読み込みエクスペリエンスをより正確に把握するために、First Meaningful Paint(FMP)や Speed Index(SI)(どちらも Lighthouse で利用可能)などのパフォーマンス指標を推奨していましたが、これらの指標は複雑で説明が難しく、間違いが多々あります。つまり、ページのメイン コンテンツがいつ読み込まれたのかはまだ特定できません。
Google は、W3C Web Performance Working Group のディスカッションと Google で行われた調査に基づき、ページのメイン コンテンツが読み込まれたタイミングをより正確に測定するには、最も大きな要素がレンダリングされたタイミングを調べる方法であることがわかっています。
LCP とは
LCP は、ビューポート内に表示される最も大きな画像、テキスト ブロック、動画のレンダリング時間を、ユーザーが最初にページに移動したタイミングと比較する形で確認できます。
高い LCP スコアとは
優れたユーザー エクスペリエンスを提供するには、サイトで Largest Contentful Paint を 2.5 秒以下に収めるようにします。ほとんどのユーザーに対してこの目標値を確実に達成するには、モバイル デバイスとデスクトップ デバイスで分けたページ読み込みの 75 パーセンタイルをしきい値として測定することをおすすめします。
どのような要素が考慮されますか?
Largest Contentful Paint で現在指定されている API などの要素の種類、 Largest Contentful Paint の場合:
<img>
要素(最初のフレームの表示時間は、GIF やアニメーション PNG などのアニメーション コンテンツに使用されます)<svg>
要素内の<image>
要素<video>
要素(ポスター画像の読み込み時間または動画の最初のフレームの表示時間のいずれか早い方)- CSS グラデーションではなく、
url()
関数を使用して読み込まれた背景画像がある要素 - テキストノードや他のインライン レベルのテキスト要素の子要素を含むブロックレベルの要素。
最初はシンプルにするために、要素をこの限定されたセットに制限しています。今後、調査が進むにつれて、<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 が発生する場合の例を以下に示します。
上記の両方のタイムラインで、コンテンツの読み込みに伴い最大要素が変化しています。最初の例では、DOM に新しいコンテンツが追加され、最も大きい要素が変更されます。2 番目の例では、レイアウトが変更され、以前は最大だったコンテンツがビューポートから削除されます。
遅れて読み込まれるコンテンツは、ページにすでに表示されているコンテンツよりも大きいことがよくありますが、必ずしもそうとは限りません。次の 2 つの例は、ページが完全に読み込まれる前に LCP が発生していることを示しています。
最初の例では、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 は測定する必要があります。 - この API では 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 のタイミングを特定し、ラボデータを使用してドリルダウンして最適化するプロセスについて説明しています。
参考情報
- Annie Sullivan が performance.now() で発表した Chrome のパフォーマンス モニタリングから得た教訓(2019 年)
変更履歴
指標の測定に使用される API でバグが見つかることがありますが、指標自体の定義に見つかることもあります。そのため、変更を加える必要がある場合があり、これらの変更は内部レポートやダッシュボードで改善または低下として表示されることがあります。
管理しやすくするために、これらの指標の実装または定義に対するすべての変更は、こちらの変更履歴で確認できます。
これらの指標についてフィードバックがある場合は、web-vitals-feedback Google グループからお寄せください。