ブラウザはどのようなプロセスでページを表示しているのか?
こんにちは、Kosukeeeです。
今回はブラウザについて取り上げてみたいと思います。
フロントエンドの書くコードは全てブラウザ上で表示されます。
ということはブラウザがどのようにしてページを表示しているのかを理解することが非常に重要になってきます。
特にtoCのサービスに関わっているとUXやSEOの観点からページの表示スピードの改善もタスクの一つになるので表示プロセスに関して理解していることが求められます。
JSやCSSは雰囲気でも書けてしまいますが、ブラウザがDOMやCSSOMをどのように解析して構築しているのかを理解することでパフォーマンス最適化されたコードにすることができます。
特に近年モバイルへの流れがより一層増したことでパフォーマンスを意識したコードを書く重要性も増しています。
この記事はプロダクトマネージャーなどエンジニア以外の方でもWebサービスに関わっている方であれば知っておいて損はないかと思います。
クリティカル・レンダリング・パス
ブラウザがページを表示するプロセスはこの「クリティカル・レンダリング・パス」という一連の流れを理解する必要があります。
ウェブページは以下の流れにしたがって表示されます。
DOMの構築 > CSSOMの構築 > レンダーツリーの構築 > レイアウト > ペイント
それではこれからそれぞれの流れを見ていきましょう。
DOM/CSSOM/レンダーツリーの構築
まず最初にブラウザからURLにアクセスするとサーバーへHTTPリクエストを投げます。そのリクエストに対してサーバーはHTTPレスポンスを返します。このレスポンスにヘッダーとデータ(本文)が入っていて、ブラウザでこのヘッダーとデータをもとにDOM(Document Object Model)を構築します。
DOMの構築には
キャラクタ > トークン > ノード > DOM
というプロセスを経て作成されます。
大抵の場合はHTMLファイルにはJSファイルとCSSファイルへの参照があるのでそれをもとにJSの場合はDOMを操作し、CSSの場合はCSSOM(CSS Object Model)を構築します。
CSSもDOMと同様に
キャラクタ > トークン > ノード > CSSOM
というプロセスを経てCSSOMを構築します。
またCSSファイルへの参照があるとDOMの構築をいったん中断してCSSファイルをダウンロード・解析してCSSOMを構築します。このようにDOMの構築を中断してしまうことをレンダーブロッキングといいます。
なのでCSSファイルが必要以上に大きいとそのぶんDOMの構築が遅くなり結果としてページの表示に時間がかかってしまいます。
また同様にJSファイルのダウンロード・実行もscriptタグに属性がないとDOMの構築を止めてしまうので必要に応じてasyncやdeferなどでJSの実行をHTMLの解析が完了した後に変更するなどの対処が必要です。
さらにこのDOMとCSSOMをもとにレンダーツリーを作成します。
このレンダーツリーをもとにして次のレイアウトのプロセスに移ります。
レイアウト
レンダーツリーが構築されると「レイアウト」のプロセスに移ります。
レイアウトとは各要素のピクセル単位のサイズをもとにどこに描画されるかを決めることです。
このレイアウトのプロセスはデバイスを回転させたり、ウィンドウをリサイズする度に発生します。
ペイント (描画)
レイアウトによってスリーンのどこに配置するかが決まると「ペイント(描画)」のプロセスに移ります。最初に一度ペイントされるとその後は変更のあった箇所だけがリペイント(再描画)されます。
リペイントにかかる時間はレンダーツリーにどのような変更があったのかによって異なります。
レンダリング最適化
以上のクリティカル・レンダリング・パスを理解しているとウェブサイトのレンダリング最適化(オプティマイゼーション)に役立ちます。
ページは最初のロード時に表示されて以降もJSからDOMやCSSOMを操作することで必要に応じて変更が発生します。
それが下記の流れになります。
JS > スタイル > レイアウト > ペイント > コンポジット
この流れを詳細に説明します。
JS:まずJSによってDOMやCSSOMへの変更というのはページのビジュアルの変更を伴います。
スタイル:どの要素に対してどのCSSルールが適用されるのかを判断して計算します。
レイアウト:要素単位での計算が終わるその要素がページ上のどの位置にどのくらいのスペースを必要とするのかという計算をします。
ペイント:ペイントというのはピクセルを埋めていくプロセスのことです。
これは「ラスタライズ」とも呼ばれます。
テキストや色、画像、ボーダーやシャドウといったすべての見える要素です。ペイントはレイヤーごとに行われます。
コンポジット:最終的にスクリーンに表示される際には正しい奥行きの順番で表示される必要があります。これがコンポジットのプロセスです。
JSの操作によっては「JS > スタイル > レイアウト > ペイント > コンポジット」の全てのプロセスを踏んでいくものもあれば「レイアウトをスキップ」するもの、または「レイアウトとペイントをスキップ」するものもあります。
そのため書いているコードがどのような変更をもたらすのか、までを理解したうえで書けるようになるとパフォーマンス最適化されたページをつくることができるようになるでしょう。
今回は以上になります。
最後までお読みいただきありがとうございました。