#はじめに

「Webサイトのパフォーマンスを改善したい」——でも、何を基準に評価すればいいのでしょうか?

Core Web Vitalsは、Googleが定義したWebページの「ユーザー体験」を測定する指標です。検索ランキングの要因にもなっており、現代のWeb開発では必須の知識です。

この記事を読むと、以下のことができるようになります:

  • 3つの Core Web Vitals の意味を理解できる
  • 各指標の測定方法がわかる
  • 改善のアプローチを把握できる

#Core Web Vitalsとは

Core Web Vitalsは、Webページのユーザー体験を3つの観点から評価する指標です。

指標測定対象良好な値
LCP読み込みパフォーマンス2.5秒以下
INPインタラクティブ性200ms以下
CLS視覚的安定性0.1以下

これらは「ラボデータ」(テスト環境)と「フィールドデータ」(実際のユーザー)の両方で測定できます。

#LCP(Largest Contentful Paint)

LCPは、ページ内で最も大きなコンテンツが表示されるまでの時間です。

#何を測定しているか

ビューポート内で最も大きい要素が描画されるタイミングを測定します。

対象となる要素:

  • <img>要素
  • <video>のポスター画像
  • 背景画像を持つ要素
  • テキストブロック(<p>, <h1>など)

#基準値

評価時間
良好2.5秒以下
改善が必要2.5秒〜4秒
不良4秒以上

#LCPを悪化させる要因

  1. 遅いサーバーレスポンス: TTFB(Time to First Byte)が長い
  2. レンダリングブロック: CSSやJSがレンダリングをブロック
  3. 遅いリソース読み込み: 画像やフォントの取得に時間がかかる
  4. クライアントサイドレンダリング: JSが実行されるまでコンテンツが表示されない

#改善アプローチ

<!-- LCP画像の優先度を上げる -->
<img src="hero.jpg" fetchpriority="high" alt="...">

<!-- LCP画像をプリロード -->
<link rel="preload" as="image" href="hero.jpg">
  • サーバーレスポンス時間の短縮(CDN、キャッシュ)
  • クリティカルCSSのインライン化
  • 画像の最適化(サイズ、フォーマット)
  • LCP要素の優先読み込み

#INP(Interaction to Next Paint)

INPは、ユーザーの操作に対するページの応答性を測定する指標です。

2024年にFID(First Input Delay)に代わって導入されました。

#何を測定しているか

クリック、タップ、キー入力から、次の画面更新までの遅延時間を測定します。ページ全体を通じて最も遅かったインタラクション(外れ値を除く)が報告されます。

[クリック] → [イベント処理] → [画面更新]
|←─────── INP ───────→|

#基準値

評価時間
良好200ms以下
改善が必要200ms〜500ms
不良500ms以上

#INPを悪化させる要因

  1. 長いJavaScript実行: メインスレッドを長時間ブロック
  2. 大きなDOMサイズ: 更新に時間がかかる
  3. 重い再レンダリング: 不必要な再描画

#改善アプローチ

// 長いタスクを分割
async function processItems(items) {
  for (const item of items) {
    await new Promise(resolve => setTimeout(resolve, 0));
    processItem(item);
  }
}

// または requestIdleCallback を使用
requestIdleCallback(() => {
  // 優先度の低い処理
});
  • 長いタスクの分割
  • 不要なJavaScriptの削除・遅延読み込み
  • DOMサイズの最小化
  • Web Workerの活用

#CLS(Cumulative Layout Shift)

CLSは、ページ読み込み中に発生する予期しないレイアウトのずれを測定します。

#何を測定しているか

ユーザーの操作なしに要素が移動した量を数値化します。

レイアウトシフトスコア = 影響を受けた領域 × 移動距離

#基準値

評価スコア
良好0.1以下
改善が必要0.1〜0.25
不良0.25以上

#CLSを悪化させる要因

  1. サイズ未指定の画像: 読み込み後にサイズが確定
  2. 動的に挿入されるコンテンツ: 広告、バナー
  3. Webフォントの読み込み: FOIT/FOUT
  4. サイズ未指定のiframe/embed

#改善アプローチ

<!-- 画像にサイズを指定 -->
<img src="photo.jpg" width="800" height="600" alt="...">

<!-- アスペクト比を維持 -->
<style>
  .image-container {
    aspect-ratio: 16 / 9;
  }
</style>
/* フォントの読み込み中もスペースを確保 */
@font-face {
  font-family: 'MyFont';
  src: url('myfont.woff2') format('woff2');
  font-display: swap;
}
  • 画像・動画にwidth/heightを指定
  • 広告スロットの事前確保
  • font-display: swapまたはoptionalの使用
  • 動的コンテンツのスペース確保

#測定方法

#ラボデータ(開発環境)

Lighthouse

  1. DevToolsを開く
  2. Lighthouseタブを選択
  3. 「Analyze page load」をクリック

PageSpeed Insights https://pagespeed.web.dev/

#フィールドデータ(実際のユーザー)

Chrome UX Report(CrUX) 実際のChromeユーザーから収集されたデータ。PageSpeed Insightsでも確認可能。

web-vitals ライブラリ

import { onLCP, onINP, onCLS } from 'web-vitals';

onLCP(console.log);
onINP(console.log);
onCLS(console.log);

#DevToolsでのリアルタイム確認

  1. DevToolsを開く
  2. 「Performance」タブを選択
  3. 「Web Vitals」チェックボックスを有効化
  4. ページをリロードして記録

#優先順位の付け方

#1. フィールドデータを確認

PageSpeed Insightsで実際のユーザーデータを確認し、どの指標が問題かを特定。

#2. 影響の大きい問題から対処

LCPが悪い → ヒーロー画像やメインコンテンツの最適化
INPが悪い → JavaScriptの実行時間を調査
CLSが悪い → レイアウトシフトの原因を特定

#3. 繰り返し測定

改善後に再測定し、効果を確認。

#よくある改善パターン

#LCP改善

<!-- 1. LCP画像をプリロード -->
<link rel="preload" as="image" href="hero.webp" type="image/webp">

<!-- 2. 優先度を上げる -->
<img src="hero.webp" fetchpriority="high" alt="...">

<!-- 3. レンダリングブロックを排除 -->
<link rel="stylesheet" href="critical.css">
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">

#INP改善

// 長いタスクを分割
function processLargeArray(array) {
  const chunk = 100;
  let index = 0;

  function processChunk() {
    const end = Math.min(index + chunk, array.length);
    for (; index < end; index++) {
      process(array[index]);
    }
    if (index < array.length) {
      setTimeout(processChunk, 0);
    }
  }

  processChunk();
}

#CLS改善

/* 画像のアスペクト比を維持 */
img {
  width: 100%;
  height: auto;
  aspect-ratio: attr(width) / attr(height);
}

/* 広告スロットを事前確保 */
.ad-slot {
  min-height: 250px;
}

#まとめ

  • LCP: 最大コンテンツの表示時間、2.5秒以下が目標
  • INP: インタラクションの応答性、200ms以下が目標
  • CLS: レイアウトの安定性、0.1以下が目標
  • ラボデータとフィールドデータの両方で測定
  • 影響の大きい問題から優先的に改善

#次のステップ

Core Web Vitalsを理解したところで、次はリソースヒントについて学びましょう。preload、prefetch、preconnectなどを使って、リソースの読み込みを最適化する方法を紹介します。

#参考リンク