Largest Contentful Paint (LCP)

Largest Contentful Paint (LCP)

更新済み
Appears in: Web Vitals|指標

Largest Contentful Paint (最大視覚コンテンツの表示時間、LCP) は、知覚される読み込み速度を測定するための重要なユーザーを中心とした指標です。これは、LCP がページの読み込みタイムラインにおいてページのメイン コンテンツが読み込まれたと思われる時点を示すためです。LCP を高速にすることで、そのページが便利であることをユーザーに強く印象付けることができるようになります。

歴史的に見ても、Web ページのメイン コンテンツがどの程度早く読み込まれ、ユーザーに対して表示されるかを測定することは Web 開発者にとっての大きな課題でした。

loadDOMContentLoaded のような古い指標は、ユーザーが画面上で見ているものとは必ずしも一致しないため、 適切ではありません。また、First Contentful Paint (視覚コンテンツの初期表示時間、FCP) のようなユーザーを中心とした新しいパフォーマンス指標は、読み込みエクスペリエンスのごく初期の部分しかキャプチャできません。特にページにスプラッシュ スクリーンや読み込みインジケーターなどが表示されている場合には、この瞬間的な出来事はユーザーにとってあまり意味がありません。

過去には、初期表示後の読み込みエクスペリエンスを把握するために First Meaningful Paint (意味のある視覚コンテンツの初期表示時間、FMP)Speed Index (スピード インデックス、SI) といったパフォーマンス指標を推奨してきました。しかしながら、これらの指標は複雑で説明が難しく、間違っている場合も多かったため、これらを使用してページのメイン コンテンツがいつ読み込まれたかを特定することはできませんでした。

物事には、シンプルな方が好ましい場合があります。W3C Web Performance ワーキング グループでの議論や Google が実施した調査によると、ページのメイン コンテンツの読み込みタイミングをより正確に測定するためには、最も大きい要素がレンダリングされるタイミングの測定が重要であることが分かりました。

LCP とは? #

Largest Contentful Paint (LCP) 指標は、ビューポート内に表示される最も大きい画像またはテキスト ブロックのレンダリング時間を、ページの初期読み込み開始タイミングと比較してレポートします。

良好なLCP値は2.5秒、不十分な値は4.0秒を超え、その間の値は改善が必要

LCP における良いスコアとは? #

良好なユーザー体験を提供するために、サイトは Largest Contentful Paint が 2.5 秒以下になるように努力する必要があります。ほぼすべてのユーザーに対してこの目標値を確実に達成するためには、モバイル デバイスとデスクトップ デバイスに分けた上で、総ページロード数の 75 パーセンタイルをしきい値として設定します。

この推奨事項の根拠となる調査および方法論に関する詳細については、「Core Web Vitals の指標のしきい値の定義」を参照してください。

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

Largest Contentful Paint API で現在規定されているように、Largest Contentful Paint については以下の要素が考慮されます。

  • <img> 要素
  • <svg> 要素内の <image> 要素
  • <video> 要素 (ポスター画像が使用されます)
  • (CSS グラデーションとは対照的に、) url() 関数を介して読み込まれた背景画像が含まれている要素
  • テキスト ノードやその他のインラインレベルのテキスト要素の子要素を含むブロックレベル要素。

なお、要素をこのように限定したのは、最初に考え方をシンプルにするという意図があったためです。研究が進むにつれて、追加の要素 (<svg><video> など) が今後追加されていく可能性があります。

要素のサイズはどのようにして決定されますか? #

Largest Contentful Paint としてレポートされる要素のサイズは、通常ビューポート内でユーザーに対して表示されるサイズとなります。要素がビューポートからはみ出していたり、要素の一部が切り取られていたり、画面に表示されないオーバーフローが発生したりしているような場合、そういった部分は要素のサイズには含まれません。

本来のサイズからリサイズされた画像要素については、表示されたサイズと本来のサイズのうち、いずれか小さい方がレポートされます。たとえば、本来のサイズよりもはるかに小さいサイズへと縮小された画像については、表示されたサイズのみがレポートされ、逆に大きなサイズへと引き伸ばされたり拡大されたりした画像については、本来のサイズのみがレポートされます。

テキスト要素については、そのテキスト ノードのサイズ (すべてのテキスト ノードを包含する最小の長方形) のみが考慮されます。

あらゆる要素において、CSS を介して適用されているマージン、パディング、ボーダーはすべて考慮されません。

どのテキスト ノードがどの要素に属しているかについての判断は時に難しいものとなり、特にインライン要素やプレーン テキスト ノードだけでなくブロックレベル要素も子要素として含んでいる要素については、特に難しくなります。この場合に重要となるのは、すべてのテキスト ノードは最も近いブロックレベルの祖先要素に属している (そして、その要素にのみ属している) という点です。仕様では、各テキスト ノードはその包含ブロックを生成する要素に属するとして定義されています。

最大視覚コンテンツはどのタイミングでレポートされますか? #

Web ページは段階的に読み込まれる場合が多く、その結果としてページ内で最も大きい要素が変更される可能性があります。

こういった変更の可能性に対応するため、ブラウザーは最初のフレームを描画した直後に、最大のコンテンツ要素を特定する largest-contentful-paint タイプの PerformanceEntry をディスパッチします。しかしながら、後続するフレームのレンダリング後に最大のコンテンツ要素が変更されるたびに、別の PerformanceEntry をディスパッチします。

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

重要なのは、ある要素についてレンダリングが完了し、ユーザーに対して表示された時点で初めて、その要素は最大のコンテンツ要素としてみなされるという点です。まだ読み込まれていない画像は、"レンダリングされた" とはみなされません。また、フォント ブロック期に Web フォントを使用するテキスト ノードについても同様です。このような場合に、比較的サイズが小さい要素が最大のコンテンツ要素としてレポートされる可能性がありますが、よりサイズの大きい要素のレンダリングが完了すれば、別の PerformanceEntry オブジェクトを介してすぐにその要素がレポートされます。

遅れて読み込まれる画像やフォントに加えて、新しいコンテンツが利用可能になったタイミングでページが新しい要素を DOM に追加する場合があります。こういった新しい要素のいずれかがそれまでの最大のコンテンツ要素よりもサイズが大きくなる場合、新しい PerformanceEntry もレポートされます。

現時点での最大のコンテンツ要素がビューポートから削除された場合 (あるいは DOM から削除された場合)、よりサイズの大きい要素がレンダリングされない限り、その要素が引き続き最大のコンテンツ要素として見なされます。

Chrome 88 より以前のバージョンでは削除された要素は最大のコンテンツ要素としては見なされず、現在の候補の削除が新しい largest-contentful-paint エントリのディスパッチのトリガーとなっていました。しかしながら、画像カルーセルのような一般的な UI パターンにおいては DOM 要素が削除されるケースが多いため、ユーザー体験をより正確に反映するためにこの指標はアップデートされました。詳細については、CHANGELOG を参照してください。

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

分析を行う場合には、直近にディスパッチされた PerformanceEntry のみをアナリティクス サービスにレポートする必要があります。

注意: ユーザーはバックグラウンド タブでページを開くこともできるため、Largest Contentful Paint はユーザーがタブにフォーカスするまで発生しない可能性があり、そのタイミングはユーザーが最初にタブを読み込んだタイミングよりもずっと後になる可能性があります。

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

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

以下の使用例では、レンダリング時間が利用できない要素の処理方法について示しています。ただし、可能な限りTiming-Allow-Origin ヘッダーを設定することを常に推奨しています。そうすることで、指標はより正確になります。

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

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

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

#

ここでは、いくつかの人気 Web サイトにおいて Largest Contentful Paint が発生する場合の例をご紹介します。

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

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

遅れて読み込まれたコンテンツの方がすでにページ上に表示されているコンテンツよりもサイズが大きいといったケースはよく見られますが、必ずしもそうなるわけではありません。次の 2 つの例では、ページが完全に読み込まれる前に Largest Contentful Paint が発生しています。

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

1 つ目の例では、Instagram のロゴの読み込みが比較的早い段階で完了し、その他のコンテンツが徐々に表示されていく中でもロゴが最大の要素となっています。Google の検索結果ページの例では、画像やロゴの読み込みが完了する前に表示されるテキストの段落が最大の要素となっています。個々の画像はすべてこの段落よりもサイズが小さいため、読み込みプロセス全体を通してこの段落がずっと最大の要素となっています。

Instagram のタイムラインの最初のフレームで、カメラのロゴに緑色のボックスがないことにお気づきの方がいらっしゃるかもしれません。これは、この要素が <svg> 要素だからであり、<svg> 要素は現段階で LCP の候補とされていません。最初の LCP 候補は、2 つ目のフレームに含まれているテキストです。

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 エントリをコンソールにログとして記録する方法を示していますが、JavaScript を使用して LCP を測定する方法はより複雑です。詳細については、以下を参照してください。

上記の例では、ログとして記録された各 largest-contentful-paint エントリが現時点での LCP 候補を表しています。一般的には最後に発行されたエントリの startTime 値が LCP 値となりますが、必ずしもそうなるわけではありません。すべての largest-contentful-paint エントリが LCP の測定に有効なわけではありません。

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

指標と API の違い #

  • API はバックグラウンド タブで読み込まれているページに対して largest-contentful-paint エントリをディスパッチしますが、LCP を計算する場合にはそういったページを無視する必要があります。
  • API はページがバックグラウンドに移行した後も largest-contentful-paint エントリをディスパッチし続けますが、LCP を計算する場合にはこういったエントリを無視する必要があります (要素が考慮されるのは、ページがずっとフォアグラウンドにあった場合のみです)。
  • API は、ページが Back/Forward Cache から復元された場合の largest-contentful-paint エントリはレポートしませんが、これらはユーザーにとっては別々のページ訪問となるため、こういったケースにおいても LCP は測定される必要があります。
  • API では iframe に含まれている要素は考慮されませんが、LCP を正確に測定するためにはこれらの要素も考慮に入れる必要があります。サブフレームが集約のために API を使用してその親フレームに largest-contentful-paint エントリをレポートすることができます。

こういった微妙な違いをすべて記憶していなくても、web-vitals JavaScript ライブラリを使用して LCP を測定すれば、これらの違いを (可能な限り) 処理してくれます。

import {getLCP} from 'web-vitals';

// 実行可能となった時点ですぐに LCP の測定やログ記録を実行します。
getLCP(console.log);

JavaScript を使用して LCP を測定する方法に関する詳細な例については、getLCP() のソース コードを参照してください。

場合によっては (クロスオリジン iframe など)、JavaScript を使用して LCP を測定することはできません。詳細については、web-vitals ライブラリの「limitations (制限事項)」セクションを参照してください。

最も重要な要素が最もサイズの大きい要素ではない場合 #

場合によっては、ページ上で最も重要な要素が最もサイズの大きい要素ではないため、開発者の方がこれらの要素以外の要素のレンダリング時間を測定したいと考える可能性があります。これは、「Custom Metrics (カスタム指標)」の記事で説明されている Element Timing API を使用すれば可能です。

LCP の改善方法 #

LCPは、主に次の 4 つの要因の影響を受けます。

  • サーバーの応答時間が遅い
  • レンダリングを妨げる JavaScript および CSS
  • リソースの読み込み時間
  • クライアント側のレンダリング

LCP の改善方法の詳細については、「LCP を最適化する」を参照してください。LCP の改善にもつながる個別のパフォーマンス改善手法に関するその他のガイダンスについては、以下を参照してください。

その他のリソース #

CHANGELOG #

Occasionally, bugs are discovered in the APIs used to measure metrics, and sometimes in the definitions of the metrics themselves. As a result, changes must sometimes be made, and these changes can show up as improvements or regressions in your internal reports and dashboards.

To help you manage this, all changes to either the implementation or definition of these metrics will be surfaced in this CHANGELOG.

最終更新: 記事を改善する