スタイル計算の範囲と複雑さを軽減

視覚的な変更は、多くの場合 JavaScript によってトリガーされます。変更は、スタイルの操作によって直接行われる場合もあれば、データの検索や並べ替えなど、視覚的な変更につながる計算によって行われる場合もあります。タイミングが悪い JavaScript や長時間実行される JavaScript は、パフォーマンスの問題の一般的な原因となるため、可能な限りその影響を最小限に抑える必要があります。

スタイルの計算

要素の追加や削除、属性やクラスの変更、アニメーションの再生によって DOM を変更すると、ブラウザは要素のスタイルを再計算し、多くの場合、ページの一部または全体のレイアウトを再計算します。このプロセスはスタイル計算と呼ばれます。

ブラウザは、一致するセレクタのセットを作成して、特定の要素に適用されるクラス、疑似セレクタ、ID を決定することで、スタイルの計算を開始します。次に、一致するセレクタのスタイルルールを処理し、要素の最終的なスタイルを特定します。

インタラクション レイテンシにおけるスタイル再計算の役割

Interaction to Next Paint(INP)は、ユーザー入力に対するページの全体的な応答性を評価する、ユーザー中心のランタイム パフォーマンス指標です。ユーザーがページを操作してから、ブラウザがユーザー インターフェースの対応する視覚的な更新を示す次のフレームをペイントするまでのインタラクション レイテンシを測定します。

インタラクションの重要な要素は、次のフレームのペイントにかかる時間です。次のフレームを表示するために行われるレンダリング処理は、レイアウト、ペイント、合成処理の直前に行われるページスタイルの計算など、多くの部分で構成されています。このガイドではスタイル計算コストに焦点を当てていますが、インタラクションの合計レンダリング時間の一部を短縮すると、合計レイテンシも短縮されます。

セレクタの複雑さを軽減する

CSS セレクタを簡素化すると、ページのスタイル計算を高速化できます。最もシンプルなセレクタは、クラス名のみを使用して CSS 内の要素を参照します。

.title {
  /* styles */
}

ただし、プロジェクトが拡大するにつれて、より複雑な CSS が必要になる可能性があり、最終的には次のようなセレクタになる可能性があります。

.box:nth-last-child(-n+1) .title {
  /* styles */
}

これらのスタイルがページにどのように適用されるかを判断するには、ブラウザは「これは、親要素のマイナス n 番目の子である box クラスの親を持つ title クラスの要素か?」という質問を効果的に行う必要があります。ブラウザがこれを把握するまでに時間がかかることがあります。これを簡素化するために、セレクタをより具体的なクラス名に変更できます。

.final-box-title {
  /* styles */
}

これらの置換クラス名は不自然に見えるかもしれませんが、ブラウザの処理を大幅に簡素化します。たとえば、以前のバージョンでは、ブラウザが要素がそのタイプの最後であることを認識するには、まず他のすべての要素についてすべてを把握し、その後に続く要素が nth-last-child であるかどうかを判断する必要がありました。これは、クラス名のみに基づいてセレクタを要素に照合するよりも、計算コストが大幅に増加する可能性があります。

スタイル設定する要素の数を減らす

パフォーマンスに関するもう 1 つの考慮事項は、要素が変更されたときに必要な作業量です。これは、セレクタの複雑さよりも重要となる場合もあります。

一般に、計算された要素のスタイルの計算の最悪ケースのコストは、要素数にセレクタ数を掛けた値です。これは、ブラウザが各要素をすべてのスタイルと少なくとも 1 回照合して、一致するかどうかを確認する必要があるためです。

スタイル計算では、ページ全体を無効にする代わりに、いくつかの要素を直接ターゲットに設定できます。最新のブラウザでは、変更の影響を受ける可能性のあるすべての要素をブラウザが常にチェックする必要がないため、この問題は軽減されています。一方、古いブラウザは、このようなタスクに最適化されているとは限りません。可能な場合は、無効な要素の数を減らす必要があります。

スタイルの再計算コストを測定する

ブラウザでスタイルの再計算のコストを測定する方法はいくつかあります。それぞれ、開発環境のブラウザで測定するのか、ウェブサイトで実際のユーザーがこの処理に要する時間を測定するのかによって異なります。

Chrome DevTools でスタイルの再計算コストを測定する

スタイルの再計算のコストを確認する方法の 1 つは、Chrome DevTools のパフォーマンス パネルを使用することです。利用を開始する手順は次のとおりです。

  1. DevTools を開きます。
  2. [パフォーマンス] タブに移動します。
  3. [セレクタの統計情報] チェックボックスをオンにします(省略可)。
  4. [録音] をクリックします。
  5. ページを操作してください。

録画を停止すると、次のような画像が表示されます。

スタイル計算を示す DevTools。
スタイル計算を示す DevTools レポート。

上部のストリップは、フレームレートもプロットするミニチュア フレームグラフです。アクティビティがストリップの下部に近いほど、ブラウザによるフレームのペイントが速くなります。炎グラフの上部が平坦になり、その上に赤いバーが表示されている場合は、フレームの長時間実行の原因となる処理があります。

Chrome DevTools のパフォーマンス パネルに表示されたアクティビティの概要で、Chrome DevTools の問題のある領域を拡大している様子。
DevTools のアクティビティの概要で長時間実行されるフレーム。

スクロールなどの操作中にフレームが長時間実行されている場合は、詳しく確認する必要があります。大きな紫色のブロックが表示された場合は、アクティビティを拡大し、[スタイルの再計算] というラベルの付いた作業を選択して、費用のかかる可能性があるスタイルの再計算作業の詳細を確認します。

長時間実行されるスタイル計算の詳細を取得する(スタイルの再計算作業の影響を受ける要素の数などの重要な情報を含む)。
DevTools の概要で、25 ミリ秒を超える長時間のスタイル再計算。

イベントをクリックすると、コールスタックが表示されます。レンダリング処理がユーザー操作によって行われた場合は、スタイル変更をトリガーした JavaScript を呼び出します。また、変更が影響する要素の数(この場合は 900 要素強)と、スタイル計算に要した時間も表示されます。この情報を使用して、コードの修正を開始できます。

トレースを行う前に [パフォーマンス パネル] の設定で [セレクタの統計情報] チェックボックスをオンにしていた場合、トレース下部のパネルに同じ名前のタブが追加されます。

Chrome DevTools のパフォーマンス パネルに表示される CSS セレクタの統計情報の表。この表には、経過時間、一致試行回数、一致数、一致しないノードの割合、セレクタ、セレクタが見つかるスタイルシートなどのヘッダーと対応するデータが含まれています。
Chrome DevTools のパフォーマンス パネルに表示されるセレクタの統計情報の表。

このパネルには、各セレクタの相対的なコストに関する有用なデータが表示されるため、コストの高い CSS セレクタを特定できます。

詳細については、CSS セレクタの統計情報のドキュメントをご覧ください。

実際のユーザーのスタイルの再計算コストを測定する

ウェブサイトの実際のユーザーに対してスタイルの再計算が行われるまでにかかる時間を把握したい場合は、Long Animation Frames API を使用すると必要なツールが提供されます。この API のデータは、スタイルの再計算時間など、web-vitals JavaScript ライブラリに追加されています。

インタラクションの表示遅延がページの INP の主な原因と思われる場合は、その時間のうち、ページのスタイルの再計算に費やされている時間の割合を把握する必要があります。詳細については、フィールドでスタイルの再計算時間を測定する方法をご覧ください。

リソース