INPを改善する最短ルートは、重そうなコードを勘で削ることではなく、遅い操作を特定し、入力遅延・処理時間・表示遅延のどこが長いか分けることです。良好の目安は75パーセンタイルで200ms以下。まず実ユーザーのフィールドデータを基準にします。
情報確認日:2026年8月20日
結論:INP改善は5段階で行う
改善ループ
- Search Console、CrUX、RUMなどのフィールドデータで問題ページを絞る
- 遅いクリック・タップ・キー操作を特定する
- 入力遅延、イベント処理、次の描画までの遅延へ分ける
- 不要処理を削り、長いタスクを分割し、DOM更新をまとめる
- ラボで回帰確認し、公開後のフィールドデータで効果を判定する
重い一括処理と分割処理を比べる
EDUCATIONAL DEMO
クリック後にメインスレッドを約120ms使う
一括処理は最初の描画を長く止めます。分割処理は途中でブラウザへ制御を返し、先に反応を描画できるようにします。
クリック→描画のローカル計測
これは端末内の説明用計測で、実サイトのINP値ではありません。
INPとは何を測る指標か
Interaction to Next Paintは、ユーザーがページを訪れている間のクリック、タップ、キーボード操作に対し、次のフレームが表示されるまでの応答性を評価します。多くの操作があるページでは代表的な遅いinteractionが指標になります。
目安は次のとおりです。ページ単体の1回のテストではなく、モバイル・デスクトップそれぞれの75パーセンタイルで判断します。
- 200ms以下:良好
- 200ms超〜500ms:改善が必要
- 500ms超:不良
1つのinteractionを3つに分ける
| 区間 | 起きていること | 主な対策 |
|---|---|---|
| 入力遅延 | 入力からイベント処理開始まで待つ | 長いタスク、第三者スクリプト、初期化を減らす |
| 処理時間 | イベントコールバックを実行 | 不要処理削除、早期return、分割 |
| 表示遅延 | 処理後から次の描画まで待つ | DOM規模、style/layout、描画量を減らす |
イベントハンドラーが短くても、その前に別の長いタスクが走っていれば入力遅延が増えます。逆に処理が終わっても大量のDOM変更でlayoutが続けば表示遅延が増えます。
まずフィールドデータで対象を絞る
PageSpeed InsightsやSearch ConsoleのCore Web Vitalsは、Chrome UX Reportの集計データを参照する入口になります。ただしURL単位の詳細な操作名までは分からないことがあります。自社でRUMを入れられるなら、web-vitalsライブラリのattribution情報と、ページ種別・端末条件を個人情報にならない形で記録します。
import { onINP } from 'web-vitals/attribution';
onINP((metric) => {
console.log({
value: metric.value,
rating: metric.rating,
interactionTarget: metric.attribution.interactionTarget,
});
});
計測コードそのものが負荷やプライバシー問題を生まないよう、サンプリング、データ保持、同意、送信先を設計します。DOMの入力値や個人情報は送らないでください。
DevToolsで遅い操作を再現する
- Performanceパネルで記録を開始する
- フィールドで疑われる操作を実行する
- 長いMain taskとイベント処理を確認する
- style recalculation、layout、paintの割合を見る
- 低速CPU条件と実機でも再確認する
高性能PCで速くても、利用者のモバイル端末では処理が数倍かかる場合があります。ラボ結果は原因究明と回帰防止に使い、合否はフィールドデータへ戻します。
改善策1:イベント処理から不要な仕事を外す
button.addEventListener('click', () => {
if (state.isSaving) return;
state.isSaving = true;
renderSavingState();
saveData();
});
二重実行を止め、ユーザーが待っている表示を先に出します。操作時に不要な全件集計、巨大JSONの変換、未表示領域の描画は後へ回せないか確認します。
改善策2:長い処理を分割して制御を返す
async function processItems(items) {
for (let index = 0; index < items.length; index += 50) {
processChunk(items.slice(index, index + 50));
await scheduler.yield();
}
}
scheduler.yield()を対象ブラウザで使えない場合は、タスク分割の代替を検討します。ただし分割回数を増やしすぎると総時間や状態管理が複雑になります。まず不要処理を削り、それでも長い処理だけを意味のある単位で分けます。
改善策3:DOM読み書きをまとめる
ループ中に寸法を読み、その直後にstyleを書き、また寸法を読むと、強制同期layoutを繰り返す原因になります。必要な値を先に読み、変更をまとめて書きます。表示件数が多い一覧は仮想化やページ分割も検討します。
const widths = cards.map((card) => card.getBoundingClientRect().width);
cards.forEach((card, index) => {
card.classList.toggle('is-wide', widths[index] > 320);
});
よくある誤解
Lighthouseが速ければINPも合格する
ラボは再現条件での診断に役立ちますが、実ユーザーが行う長時間の操作や多様な端末を完全には表しません。フィールドデータを優先します。
すべてsetTimeoutへ入れれば改善する
仕事量は減りません。重要な反応を先に描画し、不要処理を削り、残りを適切に分割する順番が必要です。
INPだけを直せばUXがよくなる
反応が速くても、結果が分からない、フォーカスが消える、エラーが伝わらないUIは使いにくいままです。状態フィードバックと操作設計も同時に確認します。
公開前後のチェックリスト
- 遅いURLと具体的な操作を記録した
- interactionを3区間へ分けてボトルネックを確認した
- 低性能端末相当と実機で回帰テストした
- クリック直後に待機中の視覚・読み上げフィードバックがある
- 公開後、十分な期間のフィールドデータで再評価する
まとめ
INP改善は、フィールドデータで遅い操作を絞り、入力遅延・処理時間・表示遅延へ分けることから始まります。仕事を削り、長いタスクを分割し、DOM更新をまとめたら、ラボで回帰を防ぎ、公開後の実ユーザーデータで効果を確かめてください。