<ph type="x-smartling-placeholder">
従来、ウェブ デベロッパーにとって、ウェブページのメイン コンテンツがどれだけ速く読み込まれてユーザーに表示されるかを測定することは困難でした。load や DOMContentLoaded などの古い指標は、ユーザーに表示される内容と必ずしも一致していないため、適切に機能しません。また、First Contentful Paint(FCP)のようなユーザー中心のパフォーマンス指標は、読み込み処理の初期段階にすぎません。ページにスプラッシュ画面や読み込みインジケーターが表示されている場合、そのタイミングはユーザーとあまり関係ありません。
これまでは、初期ペイント後の読み込みエクスペリエンスをより正確に把握できるように、First Meaningful Paint(FMP)や Speed Index(SI)(どちらも Lighthouse で利用可能)などのパフォーマンス指標を推奨していましたが、これらの指標は複雑で説明が難しく、間違いが多々あります。つまり、ページのメイン コンテンツがいつ読み込まれたのかはまだ特定できません。
Google は、W3C Web Performance Working Group のディスカッションと Google で行われた調査に基づき、ページのメイン コンテンツが読み込まれたタイミングをより正確に測定するには、最も大きな要素がレンダリングされたタイミングを調べる方法であることがわかっています。
LCP とは
LCP は、ユーザーが最初にページにアクセスしたときと比較して、ビューポートに表示される最大の画像またはテキスト ブロックのレンダリング時間をレポートします。
<ph type="x-smartling-placeholder">優れた LCP スコアとは
優れたユーザー エクスペリエンスを提供するため、サイトでは Largest Contentful Paint を 2.5 秒以下にする必要があります。ほとんどのユーザーに対してこの目標値を確実に達成するには、モバイル デバイスとデスクトップ デバイスで分けたページ読み込みの 75 パーセンタイルをしきい値として測定することをおすすめします。
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">どのような要素が考慮されますか?
Largest Contentful Paint で現在指定されている API などの要素の種類、 Largest Contentful Paint の場合:
<img>
要素(GIF やアニメーション PNG などのアニメーション コンテンツには、First-frame display time を使用します)<svg>
要素内の<image>
要素<video>
要素(ポスター画像の読み込み時間、または動画の First フレームの表示時間のうち、いずれか早いほうが使用されます)url()
関数(CSS グラデーションではない)を使用して読み込まれた背景画像がある要素- テキストノードやその他のインライン レベルのテキスト要素の子を含むブロックレベル要素。
なお、初期の作業を簡素化するために、要素をこの限定されたセットに制限したのは意図的なものです。さらなる調査の進展に応じて、要素(<svg>
の完全なサポートなど)が追加される可能性もあります。
LCP の測定では、一部の要素のみが考慮されるだけでなく、ヒューリスティックを使用して、ユーザーが「コンテンツがない」と判断する可能性の高い特定の要素も除外されます。Chromium ベースのブラウザの場合、次のものが該当します。
- ユーザーに表示されない、不透明度が 0 の要素
- コンテンツではなく背景とみなされる可能性が高い、ビューポート全体を覆う要素
- ページの実際のコンテンツを反映していない可能性が高い、エントロピーが低いプレースホルダ画像またはその他の画像
ブラウザは、最も大きなコンテンツを含む要素に対するユーザーの期待に確実に一致させるために、これらのヒューリスティックを今後も改善していく可能性があります。
これらの「コンテンツの多い」ヒューリスティックは、First Contentful Paint(FCP)で使用されるものとは異なる場合があります。FCP では、これらの要素の一部(プレースホルダ画像や完全なビューポート画像など)が、LCP の候補とならない場合でも考慮される場合があります。どちらも「contentful」という表現を使用しているにもかかわらずこれらの指標の目的は異なります。FCP は任意のコンテンツが画面にペイントされるタイミングと、メイン コンテンツがペイントされる LCP を測定し、LCP はより選択的になるようにします。
要素のサイズはどのように決定されますか?
LCP についてレポートされる要素のサイズは通常、ビューポート内でユーザーに表示されるサイズです。要素がビューポートの外側に広がっている場合、またはいずれかの要素が切り詰められているか、表示されない オーバーフロー がある場合、その部分は要素のサイズにはカウントされません。
固有のサイズからサイズ変更された画像要素の場合、レポートされるサイズは、表示サイズまたは本来のサイズのいずれか小さい方です。
テキスト要素の場合、LCP ではすべてのテキストノードを含めることができる最小の長方形のみが考慮されます。
LCP ではすべての要素について、CSS を使用して適用された余白、パディング、枠線は考慮されません。
<ph type="x-smartling-placeholder">LCP はいつ報告されますか?
ウェブページは段階的に読み込まれることが多く、そのためページの最大要素が変更される可能性があります。
このような変更の可能性に対処するため、ブラウザは最初のフレームを描画するとすぐに、largest-contentful-paint
型の PerformanceEntry
をディスパッチし、最大のコンテンツを含む要素を特定します。後続のフレームをレンダリングした後、コンテンツの最も大きい要素が変更されるたびに、別の PerformanceEntry
をディスパッチします。
たとえば、テキストとヒーロー画像を含むページの場合、ブラウザは最初にテキストをレンダリングするだけであり、その時点でブラウザは largest-contentful-paint
エントリをディスパッチします。このエントリの element
プロパティは <p>
または <h1>
を参照する可能性があります。その後、ヒーロー画像の読み込みが完了すると、2 つ目の largest-contentful-paint
エントリがディスパッチされ、その element
プロパティが <img>
を参照します。
要素は、レンダリングされてユーザーに表示された後で初めて、最大のコンテンツを含む要素と見なされます。まだ読み込まれていない画像は「レンダリングされた」とは見なされません。また、フォント ブロック期間中にウェブフォントを使用するテキストノードもありません。その場合、小さい要素が最大のコンテンツを含む要素として報告されますが、大きい要素のレンダリングが完了するとすぐに別の PerformanceEntry
が作成されます。
画像やフォントの読み込みを遅らせるだけでなく、新しいコンテンツが利用可能になると、ページから新しい要素が DOM に追加される場合があります。これらの新しい要素のいずれかが、その前にコンテンツの多い最大要素よりも大きい場合は、新しい PerformanceEntry
も報告されます。
最も大きなコンテンツの要素がビューポートや DOM から削除されても、それよりも大きな要素がレンダリングされない限り、その要素が最大のコンテンツを含む要素のままとなります。
<ph type="x-smartling-placeholder">ユーザーが(タップ、スクロール、キー操作などで)ページを操作すると、ブラウザはすぐに新しいエントリの報告を停止します。これは、ユーザー操作によってユーザーに表示される内容が頻繁に変わるためです(特にスクロールの場合はなおさらです)。
分析では、最後にディスパッチされた PerformanceEntry
のみを分析サービスにレポートする必要があります。
読み込み時間とレンダリング時間
セキュリティ上の理由から、Timing-Allow-Origin
ヘッダーのないクロスオリジン画像では、画像の表示タイムスタンプは公開されません。代わりに、読み込み時間のみが公開されます(他の多くのウェブ API を通じてすでに公開されているためです)。
そのため、ウェブ API によって LCP が FCP よりも早く報告されるという、一見ありえない状況につながりかねません。これは、このセキュリティ制限によるものです。
指標の精度を高めるため、可能な場合は常に Timing-Allow-Origin
ヘッダーを設定することをおすすめします。
要素のレイアウトとサイズ変更はどのように処理されるか?
新しいパフォーマンス エントリの計算とディスパッチのパフォーマンス オーバーヘッドを低く抑えるため、要素のサイズや位置を変更しても新しい LCP 候補は生成されません。要素の初期サイズとビューポート内の位置のみが考慮されます。
つまり、最初に画面外でレンダリングされ、画面上で遷移する画像はレポートされない可能性があります。また、要素が最初にビューポートにレンダリングされた後、押し下げられてビューから外れる場合でも、初期のビューポート内のサイズが引き続き報告されます。
例
いくつかの一般的なウェブサイトで Largest Contentful Paint が発生する場合の例を以下に示します。
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">上記のどちらのタイムラインでも、コンテンツが読み込まれると最大の要素が変化します。最初の例では、新しいコンテンツが DOM に追加され、それによって最も大きい要素が変化しています。2 番目の例では、レイアウトが変更され、以前は最大だったコンテンツがビューポートから削除されます。
遅れて読み込まれるコンテンツがページにすでにあるコンテンツよりも大きくなることはよくありますが、必ずしもそうとは限りません。次の 2 つの例は、ページが完全に読み込まれる前に LCP が発生する状況を示しています。
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">最初の例では、Instagram ロゴの読み込みが比較的早くから、他のコンテンツが少しずつ表示される場合でも、ロゴが最大の要素であり続けます。Google 検索の検索結果ページの例で最大の要素は、画像やロゴの読み込みが完了する前に表示されるテキストの段落です。個々の画像はすべてこの段落よりも小さいため、読み込みプロセス全体を通じて最大の要素のままです。
<ph type="x-smartling-placeholder">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});
<ph type="x-smartling-placeholder">
上記の例では、ログに記録された各 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 を測定しますが、事前レンダリングされたページの場合は
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()
のソースコードをご覧ください。
最大の要素が最重要ではない場合、どうすればよいでしょうか。
場合によっては、ページ上の最も重要な要素(1 つまたは複数)の最大要素と最大要素が同じではない場合、デベロッパーはそうした他の要素のレンダリング時間を測定することに興味があるかもしれません。これは Element Timing API を使用することで可能になります。詳しくは、カスタム指標に関する記事をご覧ください。
LCP を改善する方法
LCP の最適化に関する完全なガイドでは、実際の現場での LCP のタイミングを特定し、ラボデータを使用してドリルダウンして最適化するプロセスについて説明しています。
参考情報
- Annie Sullivan が performance.now() で発表した Chrome のパフォーマンス モニタリングから得た教訓(2019 年)
変更履歴
指標の測定に使用される API でバグが見つかることがありますが、指標自体の定義に見つかることもあります。そのため、変更が必要となることがあり、こうした変更は社内のレポートやダッシュボードに改善や回帰として表示されることがあります。
管理しやすくするために、これらの指標の実装または定義に対するすべての変更は、こちらの変更履歴で確認できます。
これらの指標についてフィードバックがある場合は、web-vitals-feedback Google グループからお寄せください。