アドレスバーにURLを入力してからHTTPレスポンスを得るまでには、ざっと下記のような流れを踏む。
レスポンスとしてHTMLを受け取ったところからの流れを以下にまとめた。
ブラウザ内部のソフトウェアコンポーネントのうち、画面表示に大きく関わるコンポーネントがレンダリングエンジンとJavaScriptエンジン。
HTMLの描画エンジン。Webページのレンダリングのみを担当。HTMLや画像ファイルやCSS, Javascriptなどのリソースを読み取り、それを画面上の実際のピクセルとして描画する。 ブラウザの他にも、メールクライアントのHTMLメール表示や、アプリのWebViewなどに組み込まれている。
JavaScript実行環境を提供するコンポーネント。DOMツリーやCSSOMツリーなどの内部オブジェクトやAPIに対して、JavaScriptからアクセスできるようにするバインディングが提供される。
| ブラウザ | レンダリングエンジン | JavaScriptエンジン |
|---|---|---|
| Google Chrome | Blink | V8 |
| Internet Explore | Trident | Chakra |
| Microsoft Edge | EdgeHTML | Chakra |
| Mozilla Firefox | Gecko | SpiderMonkey |
| Safari | Webkit | Nitro |
リソースのダウンロードを行う。まずはHTMLをダウンロードする。
ダウンロードしたHTMLをレンダリングエンジンが解析(Parse)し、ブラウザの内部表現であるDOMツリーに変換する。この変換過程で、ツリー内に含まれる画像やCSS, JavaScriptなどのドキュメントに紐づくリソースの取得、ダウンロードを行う。(<link>, <img>, <script>で宣言されるリソース)
CSSもまたダウンロードされたのちレンダリングエンジンにより解析され、CSSOMツリーに変換する。
DOMとは、HTMLの文書を表現するオブジェクトのこと。、HTML文書をツリー状のデータ構造として扱い、それをプログラムから参照したり操作したりするためのデータ構造やインタフェース ( API ) を定義したもの。DOMツリーは、レンダリングエンジンが利用する木構造を持つ内部表現。HTMLがDOMツリーに変換されるまでの工程は以下のとおり。
ただの文字列であるHTMLを、意味的に1つの塊となった文字列の集合(トークンのリスト)に変換する。
トークンのリストに分解されたものを使用して、構文木を構築する。構文木は木構造のデータ。
構文木に含まれるJavaScriptを同期的に実行しつつ、DOMツリーを構築する。
たとえば、document.write('SomeText');というJavaScriptがあった場合は、その実行を待って書き出された文字列を同期的にトークンの列に追加する。
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
(DOMツリーの図)
CSSを解析して、CSSOM(CSS Object Model)と呼ばれるオブジェクトツリーを構築する。
h1 {
font-size: 21px;
}
#title {
color: red;
background-color: white;
width: 200px;
}
(CSSOMツリーの図)
ダウンロードされたJavaScriptを、レンダリングエンジンはJavaScriptエンジンに引き渡して実行させる。実行の過程は以下のとおり。
JavaScriptコード
console.log('Hello, world!');
トークン列(ラベル付された文字列のリスト)
抽象構文木(JavaScriptの文法に沿った形で表現される木構造のデータ)
抽象構文木を実行可能な形式に変換する。ここでの実行可能な形式は、JavaScriptエンジンにより異なる。
DOMツリーの全てのDOM要素に対し、どのようなCSSプロパティを当てるか計算する。 CSSOMのすべてを参照し、CSSOM:DOMの総当たりでセレクタマッチングする。 このとき詳細度も算出する。
セレクタマッチングは、セレクタの右から行う。
body > .container > .button {
}
↑の場合、下記の順番で検証する。
DOMツリーのすべてのノードの視覚的レイアウト情報の計算を行う。(描画はまだしない) 視覚的レイアウト情報に含まれるのは、
内部の低レベルな2Dグラフィックエンジン向けの命令列を生成する。(ex: Skia、CoreGraphics)
Paint で生成された命令を用いて、ピクセル(ビットマップ)を描画する。このとき、レイヤーという単位で1枚ずつ描画する。 レイヤーが生成される条件は、下記のとおり。
position: absoluteなスタイルが適用されているposition: fixedなスタイルが適用されているtransform: translate3d()などのGPUで描画・合成されるプロパティを持っているopacityが指定されており、かつ投下して背景のコンテンツを表示する必要がある再レンダリングのときに再利用できる場合があり、素早く再レンダリングできるため。例えば、スクロールするときは、スクロール分だけコンテンツの表示される位置ずらせばよく、コンテンツの描画そのものは変更する必要がないため、以前描画したレイヤーが再利用される。
レイヤを合成して最終的なレンダリング結果を生成する。基本的にはCPUによって合成される。 下記の場合はGPUによって合成される。
描画が終わってからも、JavaScriptの実行やドキュメント内のイベントによってレンダリングは繰り返される。 DOM操作を行えば、3-1 Calculate Style から行われる場合もあれば、4-2 Rasterize からで十分な場合もある。 また、Ajaxで外部リソースを取得した場合など、1-1 Download から再実行される場合もある。