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

公開日: 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> があります。1 つ目(親)の <div> はノードの表示サイズをビューポートの幅の 50% に設定し、2 つ目(子)の <div> は親の 50%(ビューポートの幅の 25%)に width を設定します。

レイアウト情報の計算

レイアウト処理の出力は、ビューポート内の各要素の正確な位置とサイズを正確に取り込んだ「ボックスモデル」で、すべての相対的な測定値を画面上の絶対的なピクセルに変換する処理などが行われています。

表示されるノード、そのノードの計算済みのスタイル、形状がわかったので、この情報をもとに最終段階の処理を行うことができます。最終段階では、レンダリング ツリー内の各ノードを画面上の実際のピクセルに変換します。このステップは一般に「ペインティング」または「ラスタライズ」と呼ばれます。

ブラウザの処理量が非常に多いため、これには時間がかかります。しかし、Chrome DevTools を利用すると、上述の 3 段階すべての分析情報を得ることができます。元の「Hello World」の例で、レイアウト段階について見てみましょう。

DevTools でのレイアウトの測定

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

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

すべて完了すると、ページがビューポートに表示されます。

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

以下に、ブラウザで行われた手順を簡単にまとめます。

  1. HTML マークアップを処理して DOM ツリーを構築する。
  2. CSS マークアップを処理して CSSOM ツリーを構築する。
  3. DOM と CSSOM を組み合わせてレンダリング ツリーを作成します。
  4. レンダリング ツリーでレイアウトを実行して各ノードの形状を計算する。
  5. 個々のノードを画面にペイントします。

このデモページはシンプルに見えるかもしれませんが、ブラウザ側でかなりの処理が必要です。DOM または CSSOM が変更されると、このプロセスを繰り返して、画面上で再レンダリングが必要なピクセルを判別する必要があります。

クリティカル レンダリング パスの最適化とは、上記の手順 1~5 に要する合計所要時間を最小限に抑えるプロセスです。その結果、できるだけ短時間で画面にコンテンツをレンダリングできるようになり、初回レンダリング後の画面の更新間隔も短くなります。つまり、インタラクティブなコンテンツの場合に、高いリフレッシュ レートを実現できます。

フィードバック