「Core Web Vitals が悪い」と言われても、何がどう悪いのかが分かりにくい。指標の名前が3つ並び、それぞれ単位も基準値も違うからである。
この記事では、Core Web Vitals の3つの指標(LCP・INP・CLS)がページ表示の「どの瞬間」を測っているのかを整理する。あわせて、このブログの実ページに curl を当てて、HTML の側から読み取れる範囲の事実(読み込むファイルの種類、画像の寸法指定など)を確認する。
補足: 数値の基準は Google の web.dev で公開されているものである。本記事の実測は、手元から HTML とレスポンスヘッダーを取得して読んだものに限る。実際の訪問者が体験した値(フィールドデータ)は測っていないため、このブログの合否を判定する記事ではない。
Core Web Vitals とは、体験を3つの側面に分けたもの
Core Web Vitals は、ページを開いた人の体験を、次の3つの側面に分けて数値化したものである。
| 指標 | 見ているもの | 「良好」の目安 | 「不良」の目安 |
|---|---|---|---|
| LCP(Largest Contentful Paint) | 主要な内容が表示されるまで | 2.5秒以下 | 4秒超 |
| INP(Interaction to Next Paint) | 操作に画面が応えるまで | 200ミリ秒以下 | 500ミリ秒超 |
| CLS(Cumulative Layout Shift) | 表示が勝手にずれないか | 0.1以下 | 0.25超 |
評価は、ページ訪問の75パーセンタイルの値で行うとされている。「4人中3人がこの値以下で体験できているか」という見方で、平均値ではない。一部の遅い環境(古い端末や不安定な回線)の訪問者も、評価に含まれる。
また、以前は INP の位置に FID(First Input Delay)という指標があった。2024年3月に INP が FID に置き換わった。古い解説記事に FID と書いてあるのは、この名残である。
LCP — 「一番大きな部分」が表示された時刻
LCP は、ページを開いてから、画面内でいちばん大きな要素が描画されるまでの時間である。対象になるのは、画像、動画のポスター画像、背景画像を持つ要素、そして文字のかたまり(ブロック要素)などである。
「一番大きな要素」は固定ではなく、表示中に入れ替わる。最初は見出しが最大だったが、あとから大きな画像が表示されたら、そちらが LCP の候補になる。ページによって、LCP の正体は次のように変わる。
- ヒーロー画像やアイキャッチ画像があるページ → その画像
- 文章中心のページ → 本文の最初のテキストブロック(または見出し)
LCP が遅くなる原因は、4つの区間に分けて考える
LCP の時間は、次の4つの区間の合計である。どこが長いのかで、打ち手が変わる。
- サーバーの応答まで(TTFB: Time To First Byte)— HTML の最初の1バイトが届くまで
- LCP 要素の発見まで — 画像のURLを、ブラウザが見つけるまで
- LCP 要素の読み込みまで — 画像ファイルをダウンロードするまで
- 描画まで — 読み込んだあと、実際に画面に出すまで
「画像を軽くすれば直る」と考えがちだが、画像ファイルが小さくても、2番の「見つけるのが遅い」場合は改善しない。たとえば、画像のURLが CSS や JavaScript の中にしかない場合、ブラウザはそれらを読み込んで実行するまで画像の存在を知らない。HTML に <img> として書かれていれば、先読み(プリロードスキャナー)が早い段階で見つけてくれる。
遅延読み込み(lazy)を、LCP 要素にかけてはいけない
画像に loading="lazy" を付けると、画面に近づくまで読み込みを後回しにする。ページ下部の画像には有益だが、最初の画面に表示される大きな画像に付けると、LCP を自分で遅らせることになる。「画像には全部 lazy を付ける」という雑な適用が、よくある原因である。
WordPress のコアは、画像に自動で loading="lazy" を付ける仕組みを持つ。一方で、投稿の最初の画像など、最初の画面に出そうな画像には付けない調整も入っている。ただし、テーマが画像を独自に出力している場合は、この調整が効かないことがある。自分のサイトの最初の画像に lazy が付いていないかは、HTML のソースを見れば確認できる。
INP — 操作したあと、画面が応えるまでの時間
INP は、クリック、タップ、キー入力といった操作をしてから、次に画面が更新される(描画される)までの時間である。ページを開いている間の全操作のうち、もっとも遅いもの(実際には、操作数が多い場合は外れ値を除いたもの)が採用される。
重要なのは、INP が「ページを開いた瞬間」ではなく、開いたあとの全期間を対象にする点である。LCP が良くても、ボタンを押してから画面が固まるページは、INP が悪くなる。
INP の1回分の時間も、3つの区間に分かれる。
- 入力の遅延 — 操作したのに、ブラウザが別の処理で忙しくて、反応を始められない時間
- 処理時間 — クリックなどに紐づけたイベントハンドラー(JavaScript)の実行時間
- 表示の遅延 — 処理が終わってから、画面が実際に更新されるまでの時間
ブラウザは、JavaScript を実行している間、画面の更新や次の操作の処理を行えない(メインスレッドが占有される)。つまり INP が悪い原因の多くは、重い JavaScript がメインスレッドを長く占有していることである。WordPress サイトでは、読み込んでいるプラグインやテーマの JavaScript が多いほど、この占有が起きやすくなる。
CLS — 表示が、勝手にずれた量
CLS は、ページの表示中に、要素が予期せず動いた量の累計である。文章を読んでいる最中に広告が挿入されて、本文が下に押し出された経験があるはずである。リンクを押そうとした瞬間にレイアウトがずれて、違うリンクを押してしまう、というのが CLS の典型的な被害である。
CLS の値は、「どれだけ大きな範囲が」「どれだけ大きく」動いたかを掛け合わせた数値で、単位はない。0.1 以下が良好の目安である。
ずれの主な原因
- 幅と高さが指定されていない画像: 読み込み前は高さ0として配置され、読み込み後に押し出す
- あとから挿入される要素: 広告、埋め込み、通知バナーなど
- Webフォントの読み込み: 代替フォントと本来のフォントで文字の幅が違うと、行の折り返し位置が変わる
- スクロールや操作に応じた変化は対象外: ユーザーの操作の直後(約500ミリ秒以内)に起きたずれは、「期待されたずれ」として CLS に数えない
画像については、<img> に width と height 属性を書いておくだけで、ブラウザが読み込み前に枠を確保できる。現在のブラウザは、この2つの属性から縦横比を計算して、CSS で幅が可変になっても枠の比率を保つ。
このブログの HTML を読んでみる
実際に、このブログの記事ページを curl で取得して、HTML の側から言えることを確認した。
curl -s -D headers.txt -o page.html \
-w "ttfb=%{time_starttransfer} total=%{time_total} size=%{size_download}\n" \
https://wpmm.jp/blog/<記事のURL>/
結果の要点は次のとおりである(2026年10月6日、1回の計測。回線や時間帯で変わるため参考値)。
- ステータスは
HTTP/2 200。HTML 本体は圧縮前で約57KB - TTFB は約0.15秒、HTML の取得完了までの合計は約0.17秒
<img>はヘッダーのロゴ2つで、どちらもwidthとheightが指定されている(CLS の観点で安全な書き方)- 本文中に画像は含まれていないページだった。この場合、LCP の候補は本文の見出しやテキストブロックになる
- 読み込むスタイルシートは5つ。3つは外部の CDN(Googleフォント・アイコンフォント・コードのシンタックスハイライト)から、1つはテーマ自身のもの
最後の点は、LCP の考え方に関係する。スタイルシートは、読み込みが終わるまで描画をブロックするのが基本である。外部のスタイルシートが増えれば、その分、最初の描画は外部サーバーの応答に依存する。一方で、display=swap が付いた Webフォントは、フォントの到着を待たず、代替フォントで先に文字を表示する。この指定は、「文字が出ない時間」を避けるための設定である(その代わり、フォントが入れ替わる瞬間に、CLS の原因になりうる)。
このように、HTML を読むだけでも「何を待っているか」「画像の枠は確保されているか」は分かる。ただし、実際の LCP、INP、CLS の値は、ブラウザ上での描画や、実際の訪問者の操作で決まるため、HTML からは確定できない。
測定には「ラボデータ」と「フィールドデータ」がある
Core Web Vitals を測る方法は、大きく2種類ある。
| 種類 | 何か | 代表的な手段 |
|---|---|---|
| ラボデータ | 決まった条件で、手元や自動環境で測った値 | Lighthouse、ブラウザの開発者ツール |
| フィールドデータ | 実際の訪問者のブラウザで測られた値 | Chrome User Experience Report(CrUX)、Search Console の「ウェブに関する主な指標」 |
評価の基準になるのは、フィールドデータの方である。ラボデータは、変更の前後を同じ条件で比べることに向いている。INP のように、実際の操作が必要な指標は、ラボでは測りにくい(ラボでは代わりに、操作中の「処理のブロック時間」であるTBT(Total Blocking Time)などが目安に使われる)。
フィールドデータは、訪問者数が少ないページでは、データが十分に集まらず表示されないことがある。「数値が出ない」のは、必ずしも不具合ではない。
改善に取りかかる前に確認する順番
指標が悪いとき、闇雲に最適化プラグインを足す前に、次の順で確認する。
- どの指標が悪いのか(LCP / INP / CLS のどれか)を、フィールドデータで特定する
- どのページが悪いのかを絞る。サイト全体が一律に悪いとは限らない(画像の多いページだけ、など)
- LCP なら、LCP 要素が何かと、4つの区間のどこが長いかを見る
- INP なら、どの操作が遅いかと、メインスレッドを占有している JavaScript を特定する
- CLS なら、どの要素が動いているかを特定する(開発者ツールのパフォーマンス記録で、ずれた要素が分かる)
- 1回の変更ごとに、同じ条件で再計測して、効果を確かめる
画像の最適化が LCP に効くケースは、「画像最適化とWebP変換の基礎」で、サーバー側の圧縮は「gzip/Brotli圧縮の基礎」で扱っている。サーバー応答(TTFB)に関わるキャッシュの考え方は「Cache-ControlとETagの基礎」にまとめた。
まとめ
- Core Web Vitals は、表示(LCP)・操作(INP)・安定性(CLS)の3つの側面を測る
- 評価は75パーセンタイルのフィールドデータで行われ、ラボデータは変更の前後比較に向く
- LCP は4つの区間に分けると、打ち手が見える。lazy を最初の画像に付けない、画像のURLを HTML で見つけさせる、など
- INP は、ページを開いている間の全操作が対象。原因の多くは、メインスレッドを占有する JavaScript
- CLS は、画像の
width/height、あとから挿入される要素、Webフォントの入れ替わりで起きる - HTML を読めば、待っているもの・画像の枠の有無は分かる。ただし実際の値は、実測でしか確定しない
指標の名前に惑わされず、「どの瞬間の、誰の体験を測っているのか」から整理すると、必要な確認が見えやすくなる。