# Core Web Vitals 最適化ガイド【2026年版】— Next.js で INP・LCP・CLS を改善し、SEO と CV を伸ばす

> 2026年の Core Web Vitals（INP・LCP・CLS）を Next.js で改善する実践ガイド。最も失敗しやすい INP の潰し方、LCP を 2.5 秒未満にする画像・フォント・SSR 最適化、CLS をゼロに近づける寸法予約、フィールド計測（web-vitals / RUM）まで、本番品質の手法を実コードで解説します。

- 公開日: 2026-06-24
- 著者: 友田 陽大
- タグ: Next.js, パフォーマンス, フロントエンド, React, アクセシビリティ, アーキテクチャ設計
- URL: https://tomodahinata.com/blog/core-web-vitals-nextjs-inp-lcp-cls-optimization-guide

## 要点

- Core Web Vitalsは3指標。良好の基準はLCP 2.5秒未満・INP 200ms未満・CLS 0.1未満で、実ユーザーの75パーセンタイルで判定される
- 2026年の主戦場はINP。本質はJavaScriptの量と長さで、Server ComponentsでJSを減らし長いタスクを分割するのが効く
- LCPは画像・フォント・SSRで詰める。next/imageのpriorityとnext/fontのdisplay: swapを確実に付ける
- CLSは寸法予約で潰す。aspect-ratioとscrollbar-gutter: stableで後から現れる要素のズレを消す
- 合否はラボ（Lighthouse）でなくフィールド（CrUX / RUM）が正。web-vitalsで実ユーザー値を自前計測する

---

「速い」は感想ではなく**測れる品質**です。本記事は Next.js を前提に、推測ではなく数値で改善する手順を示します。

---

## 1. 3指標の正体と合格ライン

| 指標 | 何を測るか | 良好 | 要改善 | 不良 |
| ---- | ---------- | ---- | ------ | ---- |
| LCP（Largest Contentful Paint） | 主要コンテンツの表示速度 | 2.5秒未満 | 2.5〜4.0秒 | 4.0秒超 |
| INP（Interaction to Next Paint） | 操作への応答性 | 200ms未満 | 200〜500ms | 500ms超 |
| CLS（Cumulative Layout Shift） | レイアウトのズレ | 0.1未満 | 0.1〜0.25 | 0.25超 |

重要な前提が2つあります。

- **75パーセンタイルで判定。** 「訪問の75%が良好」でなければ合格しません。平均値が良くても、低速端末・低速回線のユーザーが足を引っ張ると落ちます。
- **フィールドデータが正。** Google が見るのは実ユーザー（CrUX）です。手元の Lighthouse スコアが100でも、現場が遅ければ不合格になります。

---

## 2. INP を潰す（2026年・最重要）

INP は「クリック・タップ・キー入力をしてから、画面が次に描画されるまで」の遅延を測ります。原因はほぼ常に**メインスレッドを塞ぐ JavaScript**です。

### 2-1. そもそも JS を送らない（最大のレバー）

React Server Components（RSC）は、サーバーで完結する処理のJSをクライアントへ送りません。**`"use client"` を最小の葉に閉じ込める**ことが INP 改善の本丸です。

```tsx
// ❌ ページ全体をクライアント化：不要な JS が大量にハイドレーションされる
"use client";
export default function Page() { /* 重い */ }

// ✅ 静的部分は RSC のまま。対話する葉だけ client にする
export default function Page() {
  return (
    <>
      <ProductInfo />        {/* RSC：JS ゼロ */}
      <AddToCartButton />    {/* "use client" の小さな葉だけ */}
    </>
  );
}
```

### 2-2. 長いタスクを分割し、メインスレッドに譲る

重い更新は `useTransition` / `useDeferredValue` で「緊急でない」と印を付け、入力の応答性を守ります。

```tsx
"use client";
import { useState, useDeferredValue } from "react";

function Search({ items }: { items: Item[] }) {
  const [query, setQuery] = useState("");
  // 入力は即時反映、重いフィルタリングは「遅延」させて応答性を確保
  const deferred = useDeferredValue(query);
  const results = useMemo(() => filterItems(items, deferred), [items, deferred]);

  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} aria-label="検索" />
      <ResultList results={results} />
    </>
  );
}
```

さらに効く手：

- **イベントハンドラを軽く。** ハンドラ内で重い計算をせず、必要なら `scheduler.yield()`（対応環境）や `setTimeout` でチャンクに分ける。
- **デバウンス / スロットル。** 連続入力・スクロール・リサイズはレート制限する。
- **サードパーティ JS を遅延。** 解析・チャット・広告は `next/script` の `strategy="lazyOnload"` などで後ろへ。
- **DOM を小さく。** 巨大リストは仮想化（ウィンドウイング）し、描画コストを抑える。

> 補足：リアルタイム編集や頻繁な再描画があるアプリ（共同編集・スコア入力など）では INP がそのまま「サクサク感」になります。状態更新の粒度設計が UX を左右します。

---

## 3. LCP を 2.5秒未満にする

LCP は「最大の要素（多くはヒーロー画像か見出し）」が見えるまでの時間です。効く順に。

### 3-1. 画像：`next/image` と `priority`

```tsx
import Image from "next/image";

// LCP になるヒーロー画像には priority を付け、プリロードさせる
<Image
  src="/hero.webp"
  alt="サービスのヒーロー画像"
  width={1200}
  height={630}
  priority            // ← LCP 画像に必須。遅延読み込みを無効化しプリロード
  sizes="100vw"
/>
```

`next/image` は自動で WebP/AVIF 変換・レスポンシブ生成・遅延読み込みを行います。**ただし LCP 画像にだけは `priority`** を付けます（付け忘れが頻出の不具合）。逆に、画面外の画像に `priority` を付けてはいけません。

### 3-2. フォント：`next/font` で FOUT/FOIT を消す

```tsx
import { Noto_Sans_JP } from "next/font/google";

const noto = Noto_Sans_JP({
  subsets: ["latin"],
  display: "swap",      // テキストを即表示（不可視待ちを避ける）
  preload: true,
});
```

`next/font` はビルド時にフォントをセルフホストし、外部リクエストを消します。`display: "swap"` で「文字が見えない時間（FOIT）」を避けつつ、`size-adjust` 相当の調整で字形差によるズレ（CLS）も抑えます。

### 3-3. サーバー：TTFB と SSR/ストリーミング

- **静的化・キャッシュ。** 可能な限り静的生成（SSG）/ ISR / PPR でサーバー処理を前倒しする。
- **ストリーミングと `<Suspense>`。** 重いデータを待たずに、まず骨組み（とLCP要素）を流す。
- **`preconnect` / `dns-prefetch`。** 必須の外部オリジン（CDN・計測）への接続を前倒しする。

---

## 4. CLS をゼロに近づける

CLS は「読み込み中に要素がガタッと動く量」です。原因は「**寸法を予約していない後から現れる要素**」に集約されます。

- **画像・動画・iframe・広告に明示寸法。** `width`/`height`（または `aspect-ratio`）を必ず指定し、領域を先に確保する。
- **フォント差し替えのズレ対策。** `next/font` ＋ `display: swap` ＋ メトリクス調整。
- **スクロールバーのズレ対策。** `scrollbar-gutter: stable` で出現時の横ズレを防ぐ（[Tailwind v4 ガイド](/blog/tailwind-css-v4-css-first-design-tokens-production-guide)参照）。
- **動的挿入は上から押し下げない。** バナー・通知は領域を予約するか、レイアウトを動かさないオーバーレイにする。
- **スケルトン UI** を実コンテンツと同じ寸法で出す。

```css
/* 後から入る要素も含め、領域を先に確保する */
.thumb {
  aspect-ratio: 16 / 9; /* 画像読込前から高さが確定し、ズレない */
}
```

---

## 5. 計測：推測をやめ、現場の数値で改善する

### 5-1. フィールド計測（実ユーザー）を自前で取る

`web-vitals` ライブラリで実ユーザーの値を収集し、分析基盤へ送ります。Next.js では `useReportWebVitals` が使えます。

```tsx
"use client";
import { useReportWebVitals } from "next/web-vitals";

export function WebVitals() {
  useReportWebVitals((metric) => {
    // 例：計測ビーコンで送信（sendBeacon は離脱時も送れる）
    const body = JSON.stringify({ name: metric.name, value: metric.value, id: metric.id });
    navigator.sendBeacon?.("/api/vitals", body);
  });
  return null;
}
```

- **ラボ（Lighthouse / PageSpeed Insights）** は再現・デバッグ用。CI に組み込み回帰を検出する。
- **フィールド（CrUX / 自前 RUM）** が合否の正。端末・回線・地域の分布を見て、75パーセンタイルを改善する。

### 5-2. 可観測性として運用する

- リリースごとに3指標を記録し、**劣化したら気づける**ようにする（回復性）。
- 指標をルート別・端末別に分解し、ボトルネックの局在を掴む。
- 「速さ」をダッシュボード化すると、改善が継続します。計測なき最適化は YAGNI 違反になりがちです。

---

## 6. Next.js 固有の効きどころ（早見表）

| 課題 | 手段 |
| ---- | ---- |
| 不要な JS が多い（INP） | RSC 化、`"use client"` を葉に限定、`next/dynamic` で遅延読み込み |
| LCP 画像が遅い | `next/image` ＋ `priority` ＋ 適切な `sizes` |
| フォントで遅延・ズレ | `next/font` ＋ `display: swap` |
| サーバー応答が遅い | SSG / ISR / PPR、`<Suspense>` ストリーミング、キャッシュ |
| サードパーティが重い | `next/script` の `strategy` 調整、必要時のみ読み込み |
| レイアウトのズレ | 寸法予約、`aspect-ratio`、`scrollbar-gutter: stable` |

「とりあえず全部最適化」ではなく、**計測で特定したボトルネックから順に**潰すのが KISS です。

---

## 7. アンチパターン

- ❌ **Lighthouse 100 で満足する。** 合否はフィールド（実ユーザー75%ile）。ラボだけ見ない。
- ❌ **ページ全体に `"use client"`。** INP 悪化の主因。対話する葉だけに限定する。
- ❌ **LCP 画像に `priority` を付け忘れる**／画面外画像に付ける。
- ❌ **画像・広告枠の寸法を指定しない。** CLS が跳ね上がる。
- ❌ **サードパーティ JS を `<head>` で同期読み込み。** メインスレッドを塞ぐ。
- ❌ **アクセシビリティを犠牲に速度を取る。** 仮想化やスケルトンでも、フォーカスと読み上げ順は維持する。

---

## 8. FAQ（よくある質問）

**Q. INP と FID は何が違う？**
A. FID は「最初の操作の遅延」だけを測りましたが、INP は**ページ滞在中の全操作**の応答性を測ります。2024年3月に INP が FID を正式に置き換えました。

**Q. Core Web Vitals は SEO 順位に影響する？**
A. ランキング要因の一つです。ただし「良好なら必ず上位」ではなく、コンテンツの質が前提。同等のコンテンツ間での差別化要因、かつ直帰率・CV を通じて間接的にも効きます。

**Q. SPA と SSR、どちらが有利？**
A. 一般に SSR / RSC が LCP・INP に有利です。クライアントへ送る JS が減り、初期描画も速いためです。

**Q. 画像最適化は `next/image` だけで十分？**
A. 大半はカバーできますが、LCP 画像の `priority`、適切な `sizes`、フォーマット（WebP/AVIF）、寸法予約まで含めて初めて効果が出ます。

**Q. どこから手を付けるべき？**
A. まず計測（フィールド）。次に最も失敗しやすい INP（JS削減）、続いて LCP（画像・フォント・SSR）、CLS（寸法予約）の順が費用対効果が高いです。

---

## まとめ：速さは「測れる品質」であり、売上に効く

Core Web Vitals は、ユーザー体験を数値化したものです。改善はそのまま、検索流入・直帰率・コンバージョンの改善につながります。

1. **計測（フィールド）から始める。** ラボだけを信じない。
2. **INP は JS を減らす。** RSC 化と `"use client"` の局所化が本丸。
3. **LCP は画像・フォント・SSR。** `priority` と `next/font` を確実に。
4. **CLS は寸法予約。** `aspect-ratio` と `scrollbar-gutter` でズレを消す。
5. **可観測性として運用する。** 劣化に気づける仕組みを持つ。

体感の速さは、プロダクトへの信頼そのものです。遅いサイトは、どれだけ機能が優れていても評価されません。

**サイトの表示速度・Core Web Vitals の改善、あるいは高速で応答性の高いアプリの新規開発が必要な場合は、お気軽にご相談ください。** 下記の事例では、複数人が同時に操作してもサクサク動く、応答性重視のリアルタイムアプリを設計・実装した過程を紹介しています。
