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

公開日: 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>

ウェブページとしてレンダリングされた HTML の例をご覧ください

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

上記の説明に基づいてレイアウト情報を計算します。

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

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

ブラウザはかなりの作業を行う必要があるため、時間がかかることがあります。ただし、Chrome DevTools を使用すると、前述の 3 つのステージすべてを把握できます。元の「Hello World」の例のレイアウト ステージを確認します。

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

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

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

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

「Hello web performance students!」と表示され、かわいい犬のミームが表示されているレンダリングされたページ。

ブラウザのステップを簡単にまとめます。

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

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

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