本文へスキップ
サイト総合診断

INP を改善する — 操作への応答性

INP(Interaction to Next Paint)は、クリック・タップ・キー入力といった操作に、ページがどれだけ速く応答するかを測る Core Web Vitals の指標です。2024 年 3 月に FID から置き換わりました。良好は 200 ミリ秒以下。遅くなる主因はメインスレッドを長く占有する JavaScript で、対策は「長いタスクを切って刻む」ことに集約されます。

執筆: 公開:

INP とは何ですか?

INP(Interaction to Next Paint)は、クリックやタップ、キー入力といった操作に対して、その結果が画面に描画されるまでの応答の速さを測る指標です。ページ滞在中に起きたほぼ全ての操作を対象にし、その中で最も遅かった応答に近い値を代表値として採用します。Core Web Vitals の 3 指標のうち、操作への反応性を担当します。

INP が対象にするのは、利用者が能動的に起こした操作です。具体的には次の 3 種類で、マウスの移動やスクロールそのものは含まれません。

  • クリック / タップ — ボタンやリンク、タブの切り替えなど
  • キー入力 — テキスト入力、フォームの操作、キーボードショートカット
  • タップ操作全般 — タッチ端末での押下も同じ扱い

ポイントは「1 回の最悪値に近い代表値」で評価される点です。100 回の操作のうち 99 回が快適でも、 1 回だけ 600 ミリ秒固まれば、その悪い体験が INP に反映されます。操作の多いページでは外れ値が緩和され、 およそ 50 回につき 1 つ最悪の操作が除外されますが、それでも「たまにしか起きない引っかかり」は隠せません。 平均で薄めて逃げられない設計になっています。

FID から INP に変わったのはなぜですか?

2024 年 3 月に、Core Web Vitals の応答性指標が FID(First Input Delay)から INP へ正式に置き換わりました。FID は最初の 1 操作の「待たされた時間」だけを測っていたため大半のサイトが合格し、実態を捉えきれていませんでした。INP は滞在中の全操作を、応答が終わるまで丸ごと測るため、体感に近い評価になります。

FID と INP は、同じ「応答性」を測る指標でありながら、見ている範囲がまったく違います。 FID は最初の操作が「処理を始めるまでに待たされた時間」しか見ていませんでした。 つまりハンドラの中身がどれだけ重くても、走り始めさえ早ければ good になってしまいます。 これが「ほぼ全サイトが合格する、意味の薄い指標」と言われた理由です。

FID と INP の違い
観点FID(旧・2024 年 3 月に廃止)INP(現行)
対象の操作最初の 1 回だけ滞在中のほぼ全操作
測る範囲処理を始めるまでの待ち時間だけ操作から次の描画までの全体
ごまかしやすさハンドラが重くても待ち時間が短ければ合格処理も描画も含むため隠せない
良好の基準100 ミリ秒以下200 ミリ秒以下

そのため、FID で合格していたサイトが INP で不合格になるのは珍しくありません。 これはサイトが遅くなったのではなく、これまで見逃されていた引っかかりが、ようやく正しく測られるようになったということです。Core Web Vitals の全体像と合わせて把握すると位置づけが掴めます。

INP はどのくらいなら良好ですか?

INP は 200 ミリ秒以下なら良好、200〜500 ミリ秒は要改善、500 ミリ秒を超えると不良と判定されます。合否は訪問者の 75 パーセンタイル値がこの基準を満たすかで決まります。平均ではなく、上位から数えて 4 分の 3 の利用者が 200 ミリ秒以下で反応を得られて、はじめて良好です。

基準は 200 ミリ秒以下で良好200〜500 ミリ秒で要改善500 ミリ秒超で不良の 3 段階です。 人間が「押した瞬間に反応した」と感じる境目がおよそ 200 ミリ秒で、そこに合わせて引かれています。 そして忘れてはならないのが「75 パーセンタイルで判定される」という点です。 高性能な端末を持つ一部の利用者が快適でも、下位 25% に入る利用者が固まりを体験していれば合格にはなりません。 開発者自身の手元の端末は速いことが多いので、「自分の環境では快適」は判断材料にならないと考えてください。

INP の遅延は何で構成されていますか?

INP の遅延は、入力遅延・処理時間・描画遅延の 3 つに分解できます。入力遅延はメインスレッドが空くまでの待ち時間、処理時間はイベントハンドラの実行時間、描画遅延はその後ブラウザが次のフレームを描くまでの時間です。どの区間が長いかで打つ手が変わるため、まず分解して原因を絞り込みます。

INP の 1 回分の遅延は、次の 3 区間の合計です。当てずっぽうで直しても数値は動かないので、まずどの区間が長いのかを特定してから対策を選びます。

INP を構成する 3 区間と対策
区間何が起きているか効く対策
① 入力遅延操作は起きたが、メインスレッドが別の処理で埋まっていて反応できない長いタスクの分割・サードパーティ JS の削減
② 処理時間イベントハンドラ(onClick など)自体の実行にかかる時間ハンドラの軽量化・重い処理の後回し・デバウンス
③ 描画遅延ハンドラは終わったが、次のフレームを描き終えるまでの時間更新する DOM を小さく保つ・複雑なレイアウトを避ける

実務で最も多いのは ① の入力遅延です。押した瞬間に、たまたま解析タグの初期化や大きな JSON の処理が走っていて、 その長いタスクが終わるまでクリックが宙に浮く、という形です。原因が自分の onClick の中身ではなく「操作した時点でメインスレッドが塞がっていたこと」にある点が、INP の分かりにくさでもあります。

INP が悪化する主な原因は何ですか?

最大の原因は、メインスレッドを長時間占有する JavaScript です。ブラウザは 1 本のメインスレッドで JavaScript の実行と画面の描画を交互に行うため、長いタスクが走っている間は操作に反応できません。解析タグや広告など後から足したサードパーティスクリプトが、気づかぬうちにこの占有を招いている例が多くあります。

ブラウザのメインスレッドは 1 本しかなく、そこで JavaScript の実行と画面の描画を交互にこなしています。 そのため、一度に 50 ミリ秒を超えて走り続けるタスク(いわゆる Long Task)があると、その間ブラウザは操作に応答できません。 INP を悪化させる典型的な発生源は次のとおりです。

  • サードパーティスクリプト — 解析・広告・チャット・A/B テストのタグ。自社コードより重いことが多く、 しかも制御しづらい。INP 悪化の犯人はここであることが非常に多い
  • 肥大化した JavaScript バンドル — 起動直後にまとめて実行される初期化処理が長いタスクになる
  • ハンドラ内での重い同期処理 — クリック 1 つで大量のデータを整形したり、巨大なリストを一度に再描画する
  • 過剰な DOM の更新 — 一度に何百ものノードを差し替えると、③ の描画遅延が伸びる

INP を改善するには何をすればよいですか?

長いタスクを短く分割し、入力ハンドラを軽く保つことが基本です。重い処理は scheduler.yield などでメインスレッドを一度解放してから実行し、まず視覚的な反応だけを即座に返します。加えて、不要なサードパーティスクリプトの削減や遅延読み込み、過剰な DOM 更新の抑制も効きます。

長いタスクを分割して刻む

最も効くのが、長いタスクを細かく区切って途中でメインスレッドを解放することです。 解放した隙にブラウザは、たまっていたクリックやキー入力を先に処理できます。 区切りには scheduler.yield() が最適で、未対応の環境では setTimeout(fn, 0)requestIdleCallback で代用します。

長いループを分割してメインスレッドを明け渡す
// ❌ 大量のデータを一気に処理する。
//    この for が回りきるまでメインスレッドは占有され、その間クリックに反応できない
function processAll(items) {
  for (const item of items) handle(item);
}

// ✅ 一定量ごとにメインスレッドを解放し、たまった操作を先に処理させる。
//    scheduler.yield() は「解放するが、この続きを優先的に再開する」ため、
//    setTimeout より順番を割り込まれにくい
async function processAll(items) {
  for (let i = 0; i < items.length; i++) {
    handle(items[i]);
    if (i % 50 === 0) {
      // scheduler.yield() 未対応の環境は次の行で代用できる(優先度は下がる):
      //   await new Promise((r) => setTimeout(r, 0));
      await scheduler.yield();
    }
  }
}

入力ハンドラを軽く保つ

ハンドラの中で重い処理まで同期実行すると、②の処理時間が丸ごと INP に乗ります。まず視覚的な反応だけを即座に返し、重い集計や通信は後回しにします。 連続入力にはデバウンスをかけ、実行回数そのものを減らすのが定石です。

ハンドラは軽く・重い処理は後回しに
// ❌ 入力のたびにハンドラ内で重い集計まで同期実行 → 一文字打つたびに固まる
searchInput.addEventListener("input", (e) => {
  const results = filterHugeList(e.target.value); // 重い
  renderResults(results);                          // 重い
});

// ✅ 入力欄への反映はブラウザに任せ、重い集計はデバウンスで後回し。
//    実行回数そのものが減るので、処理時間も入力遅延も縮む
let timer;
searchInput.addEventListener("input", (e) => {
  const value = e.target.value;
  clearTimeout(timer);
  timer = setTimeout(() => {
    renderResults(filterHugeList(value));
  }, 150);
});

サードパーティと DOM 更新を抑える

  • 不要なタグを消す — 使っていない解析・広告タグを棚卸しする。効果測定のためのタグが応答性を殺しているなら本末転倒
  • 遅延読み込みにする — 初回描画に不要なスクリプトは、操作やアイドル時間まで読み込みを遅らせる
  • DOM 更新をまとめる・小さくする — 一度に触るノードを減らし、画面外の要素は描かない

React などのフレームワークで INP を改善するには?

緊急でない状態更新を後回しにするのが要点です。React なら startTransition や useDeferredValue で、入力への即時反応と重い再描画を切り離せます。また、一度に描画する DOM を小さく保ち、長いリストは仮想スクロールで必要な分だけ描くと、1 回の更新にかかる処理時間そのものが短くなります。

React では、「すぐ反映すべき更新」と「遅れてもよい更新」を分けるのが鍵です。 検索窓の文字入力は即座に反映しつつ、その結果である重い一覧の再描画は useDeferredValuestartTransition で切り離すと、入力の応答性が保たれます。

緊急でない再描画を切り離す(React)
import { useDeferredValue, useMemo } from "react";

// 入力そのものの反映は即座に。重い一覧の再描画は「遅れてもよい更新」として切り離す。
// query が変わるとまず入力欄だけ更新され、一覧の再計算はブラウザが空いてから走る
function SearchResults({ query, allItems }) {
  const deferredQuery = useDeferredValue(query);
  const results = useMemo(
    () => filterHugeList(allItems, deferredQuery),
    [allItems, deferredQuery],
  );
  return <List items={results} />;
}

フレームワークに任せきりにせず、そもそも一度に描く DOM を小さくするのも重要です。 数千行のテーブルを丸ごと描けば、どんな最適化をしても③の描画遅延は伸びます。仮想スクロールで画面に見える分だけ描くようにすれば、1 回の更新コスト自体が下がります。

自分のサイトの INP をどう確認すればよいですか?

実ユーザーの値は Google Search Console の「ウェブに関する主な指標」や PageSpeed Insights の CrUX データで確認できます。原因の特定には、Chrome DevTools の Performance パネルで操作を記録し、長いタスクを探します。Lighthouse は操作を伴わないため INP を測れず、代わりに TBT を出す点に注意してください。

確認は「実ユーザーの数値(フィールド)」と「原因の特定(ラボ)」を分けて考えます。 合否を左右するのは前者で、CrUX の実測値だけが検索の評価に使われます。

  • 実ユーザーの値 — Google Search Console の「ウェブに関する主な指標」、または PageSpeed Insights の上部に出る CrUX データ
  • 原因の特定 — Chrome DevTools の Performance パネルで操作を記録し、赤く表示される Long Task を探す
  • 継続的な計測web-vitals ライブラリの onINP で、実ユーザーの値を自前で収集する

参考にした一次情報

関連する解説

自分のサイトは、実際どうなっているか

この記事で説明した項目は、すべて無料の診断ツールで実測できます。URL を入れるだけ・登録不要です。

無料で診断する