次のペイントに対するインタラクションを最適化する

ウェブサイトの Interaction to Next Paint を最適化する方法について説明します。

公開日: 2023 年 5 月 19 日、最終更新日: 2025 年 9 月 2 日

Interaction to Next Paint(INP)は、安定版の Core Web Vitals 指標です。ユーザーがページにアクセスしている間に発生したすべての対象となるインタラクションのレイテンシをモニタリングすることで、ユーザー インタラクションに対するページの全体的な応答性を評価します。最終的な INP 値は、最大時間を要したことがモニタリングされたインタラクションであり、外れ値は無視されることがあります。

優れたユーザー エクスペリエンスを提供するには、ウェブサイトの Interaction to Next Paint を 200 ミリ秒以下に抑える必要があります。ほとんどのユーザーに対してこの目標値を確実に達成するには、モバイル デバイスとデスクトップ デバイスに分割されたページ読み込みの 75 パーセンタイルを測定するのが適切なしきい値です。

INP の値は、200 ミリ秒以下が良好、500 ミリ秒より大きい場合は不良、その間は改善が必要と判断されます。
INP のしきい値

ウェブサイトによっては、インタラクションがほとんどまたはまったくない場合があります。たとえば、テキストと画像がほとんどで、インタラクティブ要素がほとんどまたはまったくないページなどです。また、テキスト エディタやゲームなどのウェブサイトでは、インタラクションが数百、場合によっては数千に及ぶこともあります。いずれの場合も、INP が高いと、ユーザー エクスペリエンスが損なわれるリスクがあります。

INP の改善には時間と労力がかかりますが、その見返りとしてユーザー エクスペリエンスが向上します。このガイドでは、INP を改善する方法について説明します。

INP の低下の原因を特定する

遅いインタラクションを修正する前に、ウェブサイトの INP が不良または改善が必要かどうかを示すデータが必要です。この情報を入手したら、ラボに移動して、遅いインタラクションの診断を開始し、解決に向けて作業を進めることができます。

フィールドで遅いインタラクションを見つける

INP を最適化するプロセスは、フィールド データから始めるのが理想的です。リアルユーザー モニタリング(RUM)プロバイダのフィールド データは、ページの INP 値だけでなく、INP 値の原因となった特定のインタラクション、インタラクションがページの読み込み中または読み込み後に発生したかどうか、インタラクションの種類(クリック、キー入力、タップ)など、その他の有用な情報も提供します。

RUM プロバイダに依存してフィールド データを取得していない場合は、INP フィールド データガイドで、PageSpeed Insights を使用して Chrome ユーザー エクスペリエンス レポート(CrUX)データを表示してギャップを埋めることをおすすめします。CrUX は、Core Web Vitals プログラムの Google データセットであり、INP を含む数百万のウェブサイトの指標の概要を提供します。ただし、CrUX では、RUM プロバイダから得られるような、問題の分析に役立つコンテキスト データが提供されないことがよくあります。そのため、可能であれば RUM プロバイダを使用するか、独自の RUM ソリューションを実装して CrUX で利用可能なデータを補完することをおすすめします。

ラボで遅いインタラクションを診断する

理想的には、インタラクションが遅いことを示すフィールド データが得られたら、ラボでテストを開始することをおすすめします。フィールド データがない場合は、ラボで遅いインタラクションを特定するための戦略がいくつかあります。このような戦略には、一般的なユーザーフローに沿って、その過程でインタラクションをテストすることや、ページの読み込み中(メインスレッドが最もビジーな状態になることが多い)にページを操作して、ユーザー エクスペリエンスの重要な部分で遅いインタラクションを特定することが含まれます。

インタラクションを最適化する

遅いインタラクションを特定し、ラボで手動で再現できるようになったら、次のステップは最適化です。

インタラクションは、次の 3 つのサブパートに分けることができます。

  1. 入力遅延。ユーザーがページでインタラクションを開始したときに始まり、インタラクションのイベント コールバックが実行を開始したときに終了します。
  2. 処理時間。イベント コールバックが完了するまでにかかる時間で構成されます。
  3. 表示遅延。ブラウザがインタラクションの視覚的な結果を含む次のフレームを表示するまでにかかる時間です。
メインスレッドでの操作の例。ブロッキング タスクの実行中にユーザーが入力を行います。入力はこれらのタスクが完了するまで遅延され、その後、pointerup、mouseup、クリック イベントのイベント ハンドラが実行され、次のフレームが表示されるまでレンダリングとペイントの処理が開始されます。
インタラクションのライフサイクル。イベント ハンドラの実行が開始されるまでに入力遅延が発生します。これは、メインスレッドでの長いタスクなどの要因が原因である可能性があります。その後、インタラクションのイベント ハンドラ コールバックが実行され、次のフレームが表示されるまでに遅延が発生します。

これら 3 つのサブパートの合計が、合計インタラクション レイテンシです。インタラクションの各サブパートは、インタラクションの合計レイテンシに一定の時間を要するため、インタラクションの各部分を最適化して、実行時間をできるだけ短くする方法を理解することが重要です。

入力遅延を特定して短縮する

ユーザーがページを操作すると、その操作の最初の部分が入力遅延になります。ページ上の他のアクティビティによっては、入力遅延がかなり長くなることがあります。これは、メインスレッドで発生するアクティビティ(スクリプトの読み込み、解析、コンパイルなど)、フェッチ処理、タイマー関数、または連続して発生し、互いに重複する他のインタラクションが原因である可能性があります。

インタラクションの入力遅延の原因が何であれ、インタラクションができるだけ早くイベント コールバックの実行を開始できるように、入力遅延を最小限に抑える必要があります。

起動時のスクリプト評価と長いタスクの関係

ページのライフサイクルにおけるインタラクティブ性の重要な側面は、起動時です。ページが読み込まれると、最初にレンダリングされますが、ページがレンダリングされたからといって、ページの読み込みが完了したわけではないことに注意してください。ページが完全に機能するために必要なリソースの数によっては、ユーザーがページの読み込み中にページを操作しようとする可能性があります。

ページの読み込み中にインタラクションの入力遅延を延長する要因の一つは、スクリプトの評価です。ネットワークから JavaScript ファイルが取得された後も、ブラウザにはその JavaScript を実行する前に、スクリプトを解析して構文が有効であることを確認し、バイトコードにコンパイルして、最後に実行するという作業が残っています。

スクリプトのサイズによっては、この作業によってメインスレッドで長いタスクが発生し、ブラウザが他のユーザー操作に応答するのが遅れることがあります。ページ読み込み中にユーザー入力に対するページの応答性を維持するには、ページ読み込み中に長いタスクが発生する可能性を減らし、ページの応答性を維持するために何ができるかを理解することが重要です。

イベント コールバックを最適化する

入力遅延は、INP が測定する最初の部分にすぎません。また、ユーザー操作に応じて実行されるイベント コールバックが、できるだけ早く完了するようにする必要もあります。

メインスレッドに頻繁に譲る

イベント コールバックを最適化する際の一般的なアドバイスとしては、コールバック内での処理をできるだけ少なくすることです。ただし、インタラクション ロジックが複雑な場合、エージェントの作業をわずかにしか削減できない可能性があります。

ウェブサイトでこの問題が発生している場合は、イベント コールバックの処理を個別のタスクに分割してみてください。これにより、一連の処理がメインスレッドをブロックする長いタスクになるのを防ぎ、メインスレッドで待機していた他のインタラクションをより早く実行できるようになります。

setTimeout は、タスクを分割する方法の一つです。渡されたコールバックが新しいタスクで実行されるためです。setTimeout を単独で使用することも、より人間工学的な yield のために、その使用を別の関数に抽象化することもできます。

無差別に譲歩することは、まったく譲歩しないよりも優れています。ただし、メインスレッドに譲歩するより微妙な方法があります。これには、ユーザー インターフェースを更新するイベント コールバックの直後にのみ譲歩し、レンダリング ロジックをより早く実行できるようにすることが含まれます。

レンダリング作業をより早く行えるように譲る

より高度な譲歩手法では、イベント コールバックのコードを構造化して、次のフレームのビジュアル アップデートを適用するために必要なロジックのみを実行するように制限します。それ以外はすべて、後続のタスクに延期できます。これにより、コールバックが軽量かつ迅速に保たれるだけでなく、ビジュアル アップデートがイベント コールバック コードをブロックしないため、インタラクションのレンダリング時間が短縮されます。

たとえば、入力時にテキストの書式を設定するだけでなく、入力内容に応じて UI の他の要素(単語数、スペルミスのハイライト表示、その他の重要な視覚的フィードバックなど)を更新するリッチテキスト エディタを考えてみましょう。また、アプリケーションは、ユーザーが離れて戻ってきたときに作業内容が失われないように、ユーザーが書いた内容を保存する必要がある場合もあります。

この例では、ユーザーが入力した文字に応じて、次の 4 つの処理を行う必要があります。ただし、次のフレームが表示される前に完了する必要があるのは、最初の項目のみです。

  1. ユーザーが入力した内容でテキスト ボックスを更新し、必要な書式設定を適用します。
  2. 現在の単語数を表示する UI の部分を更新します。
  3. スペルミスをチェックするロジックを実行します。
  4. 最新の変更を保存します(ローカルまたはリモート データベース)。

これを行うコードは次のようになります。

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

次の図は、重要でない更新を次のフレームまで遅らせることで、処理時間を短縮し、全体的なインタラクション レイテンシを短縮する方法を示しています。

2 つのシナリオにおけるキーボード操作と後続のタスクの図。上の図では、レンダリングに不可欠なタスクと、それに続くすべてのバックグラウンド タスクが、フレームを表示する機会が訪れるまで同期的に実行されます。下の図では、レンダリングに不可欠な処理が最初に実行され、その後メインスレッドに譲ることで、新しいフレームがより早く表示されます。その後、バックグラウンド タスクが実行されます。
図をクリックすると、高解像度バージョンが表示されます。

上記のコード例で requestAnimationFrame() 呼び出し内で setTimeout() を使用することは、確かに少し難解ですが、すべてのブラウザで機能し、重要でないコードが次のフレームをブロックするのを防ぐ効果的な方法です。

レイアウト スラッシングを回避する

レイアウト スラッシング(強制同期レイアウトとも呼ばれます)は、レイアウトが同期的に発生するレンダリング パフォーマンスの問題です。これは、JavaScript でスタイルを更新してから、同じタスクでスタイルを読み取るときに発生します。JavaScript には、レイアウト スラッシングを引き起こす可能性のあるプロパティが多数あります。

Chrome DevTools のパフォーマンス パネルに表示されるレイアウト スラッシングの可視化。
Chrome DevTools のパフォーマンス パネルに表示されるレイアウト スラッシングの例。レイアウト スラッシングを伴うレンダリング タスクは、コールスタックの部分の右上隅に赤い三角形で示されます。多くの場合、[Recalculate Style] または [Layout] というラベルが付いています。

レイアウト スラッシングは、パフォーマンスのボトルネックになります。JavaScript でスタイルを更新した直後にそれらのスタイルの値をリクエストすると、ブラウザは同期レイアウト作業を強制的に実行することになります。本来であれば、イベント コールバックの実行が完了した後に非同期で実行されるのを待つことができます。

表示の遅延を最小限に抑える

インタラクション マークのプレゼンテーション遅延は、インタラクションのイベント コールバックの実行が完了してから、ブラウザが結果の視覚的な変化を示す次のフレームをペイントできるようになるまでの期間です。

DOM サイズを最小限に抑える

ページの DOM が小さい場合、通常、レンダリング作業はすぐに完了します。ただし、DOM が非常に大きくなると、レンダリング処理は DOM サイズの増加に伴ってスケールする傾向があります。レンダリング作業と DOM サイズの関係は線形ではありませんが、DOM が大きいほど、レンダリングに必要な作業が増えます。DOM が大きいと、次の 2 つのケースで問題になります。

  1. ページの初期レンダリング時。DOM が大きいと、ページの初期状態をレンダリングするために多くの作業が必要になります。
  2. ユーザー操作への応答。DOM が大きいと、レンダリングの更新に非常にコストがかかり、ブラウザが次のフレームを表示するまでの時間が長くなります。

大規模な DOM を大幅に削減できない場合があることに注意してください。DOM サイズを小さくするために、DOM をフラット化したり、ユーザー操作中に DOM に追加して初期 DOM サイズを小さくしたりするなどの方法がありますが、これらの手法には限界があります。

content-visibility を使用して、画面外の要素を遅延レンダリングする

ページ読み込み時のレンダリング作業とユーザー操作に応じたレンダリング作業の両方を制限する方法の一つは、CSS の content-visibility プロパティを利用することです。これにより、ビューポートに近づいた要素を遅延レンダリングできます。content-visibility を効果的に使用するには、ある程度の練習が必要ですが、レンダリング時間が短縮され、ページの INP が改善されるかどうかを調査する価値はあります。

JavaScript を使用して HTML をレンダリングする際のパフォーマンス コストに注意する

HTML があるところには HTML 解析があります。ブラウザは HTML を DOM に解析し終えると、スタイルを適用し、レイアウト計算を実行して、そのレイアウトをレンダリングする必要があります。これは避けられないコストですが、HTML をレンダリングする方法が重要です。

サーバーが HTML を送信すると、ストリームとしてブラウザに届きます。ストリーミングとは、サーバーからの HTML レスポンスがチャンク単位で到着することを意味します。ブラウザは、ストリームのチャンクが到着するたびに段階的に解析し、少しずつレンダリングすることで、ストリームの処理方法を最適化します。これは、ブラウザがページの読み込み中に暗黙的に定期的かつ自動的に yield するという点で、パフォーマンスの最適化であり、無料で利用できます。

ウェブサイトへの最初のアクセスでは、常にある程度の HTML が必要になりますが、一般的なアプローチでは、最初に最小限の HTML を読み込み、その後 JavaScript を使用してコンテンツ領域にデータを入力します。そのコンテンツ領域に対するその後の更新も、ユーザー操作の結果として発生します。これは通常、シングルページ アプリケーション(SPA)モデルと呼ばれます。このパターンの欠点は、クライアントで JavaScript を使用して HTML をレンダリングすると、その HTML を作成するための JavaScript 処理のコストが発生するだけでなく、ブラウザがその HTML の解析とレンダリングを完了するまで処理を中断しないことです。

ただし、SPA ではないウェブサイトでも、インタラクションの結果として JavaScript による HTML レンダリングが多少行われる可能性があることに注意してください。クライアントで大量の HTML をレンダリングしない限り、これは一般的に問題ありません。大量の HTML をレンダリングすると、次のフレームの表示が遅れる可能性があります。ただし、このアプローチがブラウザでの HTML のレンダリングに与えるパフォーマンスへの影響と、JavaScript を使用して大量の HTML をレンダリングする場合に、ユーザー入力に対するウェブサイトの応答性に与える影響を理解することが重要です。

まとめ

サイトの INP の改善は反復的なプロセスです。フィールドで遅いインタラクションを修正すると、特にウェブサイトで多くのインタラクションが提供されている場合は、他の遅いインタラクションが見つかり、それらも最適化する必要が生じる可能性があります。

INP を改善する鍵は、継続的な取り組みです。時間をかけて、ユーザーが満足できるエクスペリエンスを提供できるレベルまでページの応答性を高めることができます。また、ユーザー向けの新しい機能を開発する際にも、ユーザーに固有のインタラクションを最適化するために同じプロセスが必要になる可能性があります。時間と労力はかかりますが、それだけの価値はあります。