ブラウザはページをレンダリングする前に、DOM ツリーと CSSOM ツリーを構築する必要があります。そのため、できるだけ早く HTML と CSS の両方をブラウザに配信する必要があります。
まとめ
- バイト → 文字 → トークン → ノード → オブジェクト モデル。
- HTML マークアップはドキュメント オブジェクト モデル(DOM)に変換され、CSS マークアップは CSS オブジェクト モデル(CSSOM)に変換されます。
- DOM と CSSOM は、独立したデータ構造です。
- Chrome DevTools の [Performance] パネルでは、DOM と CSSOM の構築と処理のコストを把握して検査できます。
ドキュメント オブジェクト モデル(DOM)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
いくつかのテキストと 1 つの画像を含むプレーン HTML ページという、最もシンプルなケースから説明します。ブラウザはこのページをどのように処理しますか?
- 変換: ブラウザは、ディスクまたはネットワークから HTML の未加工バイトを読み取り、ファイルの指定されたエンコード(UTF-8 など)に基づいて個々の文字に変換します。
- トークン化: ブラウザは、W3C HTML5 標準で規定されている「<html>」、「<body>」などの文字列と、山かっこで囲まれた文字列を個別のトークンに変換します。各トークンには、特別な意味と独自のルールセットがあります。
- 語彙: 出力されたトークンは「オブジェクト」に変換され、オブジェクトでプロパティとルールが定義されます。
- DOM 構成: HTML マークアップは異なるタグ間の関係を定義するため(一部のタグは他のタグに含まれているため)、作成されたオブジェクトは元のマークアップで定義された親子関係も取得されるツリーデータ構造でリンクされます。HTML オブジェクトは body オブジェクトの親、body は paragraph オブジェクトの親になります。
このプロセス全体の最終的な出力は、シンプルなページのドキュメント オブジェクト モデル(DOM)です。ブラウザはこれを以降のすべての処理に使用します。
ブラウザは HTML マークアップを処理するたびに、バイトから文字への変換、トークンの識別、トークンのノードへの変換、DOM ツリーの構築など、前述のすべてのステップを実行します。特に処理する HTML が多い場合、このプロセス全体には時間がかかることがあります。
Chrome DevTools を開いて、ページの読み込み中にタイムラインを記録すると、このステップの実行にかかった実際の時間を確認できます。上記の例では、HTML のまとまりを DOM ツリーに変換するのに約 5 ミリ秒かかっています。ページが大きい場合は、このプロセスが大幅に時間がかかることがあります。スムーズなアニメーションを作成する場合、ブラウザで大量の HTML を処理しなければならない場合に、これがボトルネックになる可能性があります。
DOM ツリーは、ドキュメント マークアップのプロパティと関係性をキャプチャしますが、レンダリング時に要素がどのように見えるかについては説明しません。それが CSSOM の責任です。
CSS オブジェクト モデル(CSSOM)
ブラウザがシンプルなページの DOM を作成しているときに、ドキュメントの head セクションで外部 CSS スタイルシートを参照するリンクタグ(style.css
)に遭遇しました。ページのレンダリングにこのリソースが必要であると予測すると、すぐにこのリソースに対するリクエストが送信され、次の内容が返されます。
body {
font-size: 16px;
}
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
スタイルを HTML マークアップ内で直接(インラインで)宣言することもできますが、CSS を HTML から独立させることで、コンテンツとデザインを別々の問題として扱うことができます。デザイナーは CSS に、デベロッパーは HTML に集中できます。
HTML と同様に、受け取った CSS ルールを、ブラウザが理解して処理できるものに変換する必要があります。そのため HTML のプロセスを繰り返しますが ここでは HTML ではなく CSS について考えます
CSS のバイトは文字、トークン、ノードに変換され、最終的に「CSS オブジェクト モデル」(CSSOM)と呼ばれるツリー構造にリンクされます。
CSSOM がツリー構造になっているのはなぜですか。ページ上のオブジェクトの最終的なスタイルセットを計算する際、ブラウザはそのノードに適用される最も汎用的なルール(たとえば、body 要素の子である場合、すべての body スタイルが適用される)から開始し、より具体的なルールを適用して計算されたスタイルを再帰的に絞り込みます。つまり、ルールを「カスケード ダウン」します。
より具体的に、上記の CSSOM ツリーを考えてみます。<span>
タグ内に含まれ、body 要素内に配置されるテキストは、フォントサイズが 16 ピクセルで、テキストが赤色です。font-size
ディレクティブは、body
から span
にカスケード ダウンします。ただし、span
タグが段落(p
)タグの子である場合、そのコンテンツは表示されません。
なお、上記のツリーは完全な CSSOM ツリーではなく、スタイルシートでオーバーライドするスタイルのみを示しています。どのブラウザでも、デフォルトのスタイルセットが用意されており、「ユーザー エージェント スタイル」とも呼ばれています。独自のスタイルを指定しない場合は、このスタイルが適用されます。スタイルは、これらのデフォルトをオーバーライドするだけです。
CSS 処理にかかる時間を確認するには、DevTools でタイムラインを記録し、「Recalculate Style」イベントを探します。DOM 解析とは異なり、タイムラインには個別の「Parse CSS」エントリは表示されず、この 1 つのイベントで解析と CSSOM ツリー構築と、計算済みスタイルの再帰計算がキャプチャされます。
この簡単なスタイルシートの処理は 0.6 ミリ秒ほどかかり、ページ上の 8 つの要素に影響します。その影響はそれほど多くありませんが、繰り返しになりますが、無料ではありません。では 8 つの要素はどこから来たのでしょうか?CSSOM と DOM は、独立したデータ構造です。ブラウザが重要なステップを隠していることがわかりました。次に、DOM と CSSOM をリンクするレンダリング ツリーについて説明します。