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

ウェブサイトの 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、click のイベント ハンドラが実行され、次のフレームが表示されるまでレンダリングとペイントの作業が開始されます。
インタラクションのライフサイクル。入力遅延は、イベント ハンドラが実行を開始するまで発生します。これは、メインスレッドでの長いタスクなどの要因が原因である可能性があります。インタラクションのイベント ハンドラ コールバックが実行され、次のフレームが表示される前に遅延が発生します。

これら 3 つのサブパートの合計が、インタラクションの合計レイテンシです。インタラクションのすべてのサブパートは、インタラクションの合計レイテンシに一定の時間を費やします。そのため、インタラクションの各パートをできるだけ短い時間で実行できるように最適化する方法を知ることが重要です。

入力遅延を特定して軽減する

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

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

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

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

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

スクリプトのサイズによっては、この処理によってメインスレッドで長時間実行タスクが発生し、ブラウザが他のユーザー操作に応答するまでの時間が長くなる可能性があります。ページの読み込み中にユーザー入力にページが応答し続けるようにするには、ページの読み込み中に長いタスクが発生する可能性を減らして、ページがスムーズに動作するようにすることが重要です。

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

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

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

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

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

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

無差別に yield するのは、まったく yield しないよりはましですが、メインスレッドに yield するには、より微妙な方法があります。それは、ユーザー インターフェースを更新するイベント コールバックの直後にのみ 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 よりもレンダリングに多くの作業を必要とします。大きな DOM は、次の 2 つのケースで問題になります。

  1. 初期ページのレンダリング時。大規模な DOM では、ページの初期状態をレンダリングするのに多くの作業が必要になります。
  2. ユーザーの操作に対する応答。DOM サイズが大きいと、レンダリングの更新にコストがかかり、ブラウザが次のフレームを表示するまでの時間が長くなる可能性があります。

大規模な DOM を大幅に削減できない場合もあります。DOM をフラット化するユーザー操作中に DOM に追加するなど、DOM サイズを小さくするためのアプローチはありますが、これらの手法には限界があります。

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

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

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

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

サーバーから HTML が送信されると、ストリームとしてブラウザに届きます。ストリーミングとは、サーバーからの HTML レスポンスがチャンク単位で届くことを意味します。ブラウザは、ストリームのチャンクが到着するたびに増分解析し、ビットごとにレンダリングすることで、ストリームの処理方法を最適化します。これは、ブラウザがページ読み込み中に定期的に自動で暗黙的にイールドするため、パフォーマンスの最適化になります。

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

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

まとめ

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

INP を改善するうえで重要なのは、粘り強さです。時間をかけて、ユーザーが満足するようなレスポンシブなページにすることができます。ユーザー向けの新しい機能を開発する際に、ユーザー固有のインタラクションを最適化する同じプロセスが必要になる可能性もあります。時間と労力はかかりますが、それだけの価値はあります。

ヒーロー画像は UnsplashDavid Pisnoy 氏によるもので、Unsplash ライセンスに従って変更されています。