レンダリング ツリーの構築、レイアウト、ペイント

公開日: 2014 年 3 月 31 日

CSSOM ツリーと DOM ツリーはレンダリング ツリーに結合され、各可視要素のレイアウトを計算するために使用されます。また、画面にピクセルをレンダリングするペイント プロセスの入力としても使用されます。最適なレンダリング パフォーマンスを実現するには、これらの各ステップを最適化することが重要です。

オブジェクト モデルの構築に関する前のセクションでは、HTML と CSS の入力に基づいて DOM ツリーと CSSOM ツリーを構築しました。ただし、これらはどちらもドキュメントの異なる側面をキャプチャする独立したオブジェクトです。1 つはコンテンツを記述し、もう 1 つはドキュメントに適用する必要があるスタイルルールを記述します。この 2 つを統合して、ブラウザで画面にピクセルをレンダリングするにはどうすればよいでしょうか?

概要

  • DOM ツリーと CSSOM ツリーが結合されて、レンダリング ツリーが形成されます。
  • レンダリング ツリーには、ページのレンダリングに必要なノードのみが含まれます。
  • レイアウトは、各オブジェクトの正確な位置とサイズを計算します。
  • 最後のステップはペイントです。最終的なレンダリング ツリーを受け取り、ピクセルを画面にレンダリングします。

まず、ブラウザは DOM と CSSOM を「レンダリング ツリー」に結合します。レンダリング ツリーは、ページ上のすべての表示可能な DOM コンテンツと、各ノードのすべての CSSOM スタイル情報をキャプチャします。

DOM と CSSOM が組み合わされてレンダリング ツリーが作成される

レンダリング ツリーを構築するために、ブラウザは概ね次の処理を行います。

  1. DOM ツリーのルートから、表示されている各ノードをトラバースします。

    • 一部のノード(スクリプトタグ、メタタグなど)は表示されず、レンダリングされた出力に反映されないため、省略されます。
    • 一部のノードは CSS を使用して非表示にされ、レンダリング ツリーからも除外されます。たとえば、上記の例の span ノードは、「display: none」プロパティを設定する明示的なルールがあるため、レンダリング ツリーから除外されます。
  2. 表示されている各ノードについて、適切な CSSOM ルールを見つけて適用します。

  3. コンテンツと計算されたスタイルを含む表示可能なノードを出力します。

最終的な出力は、画面に表示されるすべてのコンテンツのコンテンツとスタイルの両方の情報を含むレンダリング ツリーです。レンダリング ツリーが作成されたら、「レイアウト」の段階に進みます。

ここまでで、どのノードを表示すべきか、またその計算済みスタイルを計算しましたが、デバイスのビューポート内での正確な位置とサイズは計算していません。これが「レイアウト」ステージ(「リフロー」とも呼ばれます)です。

ページ上の各オブジェクトの正確なサイズと位置を特定するために、ブラウザはレンダリング ツリーのルートからトラバースを開始します。次の例を考えてみましょう。

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

試してみる

前の例の <body> には、2 つのネストされた <div> が含まれています。最初の(親)<div> は、ノードの表示サイズをビューポート幅の 50% に設定します。2 番目の <div>(親に含まれる)は、その width を親の 50%、つまりビューポート幅の 25% に設定します。

レイアウト情報を計算しています

レイアウト プロセスの出力は「ボックスモデル」です。これは、ビューポート内の各要素の正確な位置とサイズを正確にキャプチャします。すべての相対測定値は、画面上の絶対ピクセルに変換されます。

最後に、どのノードが表示されるか、その計算されたスタイルとジオメトリがわかったので、この情報を最終ステージに渡します。このステージでは、レンダリング ツリー内の各ノードが画面上の実際のピクセルに変換されます。このステップは、「ペイント」または「ラスタライズ」と呼ばれることがよくあります。

ブラウザが多くの処理を行う必要があるため、この処理には時間がかかることがあります。ただし、Chrome DevTools を使用すると、前述の 3 つのステージすべてについてある程度の情報を得ることができます。元の「hello world」の例のレイアウト ステージを調べます。

DevTools でレイアウトを測定する

  • [レイアウト] イベントは、タイムラインでレンダリング ツリーの構築、位置、サイズの計算をキャプチャします。
  • レイアウトが完了すると、ブラウザは「Paint Setup」イベントと「Paint」イベントを発行し、レンダリング ツリーを画面上のピクセルに変換します。

レンダリング ツリーの構築、レイアウト、ペイントの実行に必要な時間は、ドキュメントのサイズ、適用されたスタイル、実行されているデバイスによって異なります。ドキュメントが大きいほど、ブラウザの処理が増えます。スタイルが複雑であるほど、ペイントにかかる時間も長くなります(たとえば、単色はペイントのコストが低く、ドロップ シャドウは計算とレンダリングのコストが高くなります)。

ページがビューポートに表示されます。

レンダリングされた Hello World ページ

ブラウザの手順の概要は次のとおりです。

  1. HTML マークアップを処理して DOM ツリーを構築します。
  2. CSS マークアップを処理し、CSSOM ツリーを構築します。
  3. DOM と CSSOM を結合してレンダリング ツリーを作成します。
  4. レンダリング ツリーでレイアウトを実行して、各ノードのジオメトリを計算します。
  5. 個々のノードを画面に描画します。

デモページは基本的なものに見えますが、ブラウザ側ではかなりの作業が必要です。DOM または CSSOM のいずれかが変更された場合は、画面上で再レンダリングする必要があるピクセルを特定するために、プロセスを繰り返す必要があります。

クリティカル レンダリング パスの最適化とは、上記のシーケンスのステップ 1 ~ 5 の実行にかかる合計時間を最小限に抑えるプロセスです。これにより、コンテンツが可能な限り速く画面にレンダリングされ、初回レンダリング後の画面更新の間隔も短縮されます。つまり、インタラクティブなコンテンツのリフレッシュ レートが高くなります。

フィードバック