Web全般

レンダリングは実際何をしているのか

Web developmentWeb全般

こちらの記事でSPA・SSR・SSGの違いについてまとめたのですが、その中でレンダリングについても調べたので理解を整理していきます。

フロントエンドエンジニアとしてマストな知識なのに、それまでは、「レンダリングはWebブラウザに表示してくれること」くらいで、何も理解できてませんでした..(反省)

ブラウザがWebページを表示する流れ

まず、全体の流れはこんな感じ↓

詳しく見ていきます。

データをダウンロード

まず、ブラウザはネットワークを経由してデータをもらいます。

インターネットを通してもらうので、ファイル形式は実際に書かれたコードではなくて、バイトです。パケット通信のバイトですね。

ブラウザが理解できる形式に変換する

バイトをもらってもブラウザは理解ができないので、変換作業をしていきます。

流れはこちら↓

Bytes → Characters(文字) → Tokens → Nodes → DOM

画像に alt 属性が指定されていません。ファイル名: full-process.png
引用:ドキュメント オブジェクト モデル(DOM)

Characters(文字)に変換

ファイルに指定されたエンコード方法(UTF-8)に基づいて文字形式に変換します。

(よく書くUTF-8って、ここで使うのか!という独り言)

Tokens(トークン)に変換

文字に変換されましたが、単なるテキストなのでまだやることがあります。

今度はトークンと呼ばれる形式に変換します。

トークン化とは、ファイル形式に沿って意味のある文字列ドキュメントを作ることです。

ファイル形式が.htmlの場合、<html><body>などのタグをルールに従って解析して、個々のトークンに変換していきます。

(タグの始めと終わりを解析して、一つ一つの固有の意味とルールがあるデータ構造にしていく)

NodesからDOM生成へ

トークンが出来上がったらノードを生成します。

この辺りから何となく馴染みが出てきますね。

ノードとはDOMを構成する一つ一つの単位です。

<body><p>などのタグから、テキストなど全てがノードです。

そしてノードが一体化し、親子関係や兄弟関係も反映しているDOMツリーが出来上がります。

DOMとは、Document Object Modelの略。

HTML や XML 文書のためのプログラミングインターフェイスです。ページを表現するため、プログラムが文書構造、スタイル、内容を変更することができます。 DOM は文書をノードとオブジェクトで表現します。そうやって、プログラミング言語をページに接続することができます。

MDN – DOMの紹介

難しいので引用しました。簡単に理解するとJavaScriptで操作できるようにする仕組みですね。

(この辺はもう少し深掘りして理解したいので、またの機会に記事にしようかな…)

また、流れとしてCSSやJavaScriptのファイルではなく、常にHTMLのファイル(index.html)が最初にDOMに変換されます。常に!

ブラウザはHTMLを処理する度に上記の一連の流れを実行しているので、大量のHTMLになればなるほど、処理速度に時間がかかってしまいます。

CSSの処理の流れは?

上記の流れはHTMLファイルの話でした。

CSSのスタイルシートは、HTMLファイルの<head>の中にリンクされていますね。

<head>
  <link rel="stylesheet" href="main.css" />
</head>

HTMLファイルが解析されている時にこのstylesheetリンクに遭遇したら、cssファイルのデータをバイト形式で取得します。

CSSファイルもHTMLと同じような流れで、CSSOMというCSSオブジェクトモデルに変換されます。(CSS版のDOM)

Bytes → Characters(文字) → Tokens → Nodes → CSSOM

CSSについては、「カスケードダウン」というルールが適用されます。

このルールは、どのように各エレメントにスタイルを適用していくかを決めていことです。

例えば、<body>の子要素は<body>のスタイルが適用されるみたいに一般的なルールから開始していきます。<p>タグに何かスタイルが指定されていれば、そちらの方を上書きする。みたいな流れでどんどん計算をし再調整して行きます。

そうやって計算していき最終的なスタイルが決まるので、CSSについてもツリー構造をしています。

レンダーツリーが出来上がる

HTMLのDOMCSSのCSSOMは独立したツリーオブジェクトです。

これらを合体して、レンダーツリーが構築されます。

DOM(コンテンツ表示) + CSSOM(スタイルルール) = レンダーツリー

DOM と CSSOM を組み合わせてレンダリング ツリーを作成
引用:レンダリング ツリーの構築、レイアウト、ペイント

レンダーツリーでは、ページに表示されるDOMのみを反映します。

メタタグやスクリプトタグ、CSSで display: noneが適用されていたら省略されます。

ちなみに、visibility: hidden については、省略されず、空のボックスとしてレンダリングされます。

(レンダーツリーにあるか無いかが、accessibilityと繋がっているのか!と独り言)

CSSOMルールが各ノードに適用されていき、次のステップ「レイアウト」に移ります。

レイアウト(別名:リフロー)段階

ここまで、表示されるノードと各々に計算済みのスタイルが適用されていますね。

ページに表示するために、端末のサイズ(viewport)ごとにノードの正確なサイズとポジションを考慮する必要があります。

レイアウトでは、このviewport内で正確な位置やサイズを計算し、絶対的なピクセルなどに変換される処理が行われます。

画面にペインティングされる

遂にきました、ペインティングです。これでやっと各ノードが画面にペイントされるのです。

レンダリングブロックとは?

レンダリングブロックとは、ブラウザに表示するのをブロックすることです。(そのまま)

レンダリングブロックリソース

CSSはレンダリングブロックリソースです。なので、処理済みのコンテンツがあったとしても、CSSOMツリーが構築されるまでは、ブラウザに表示されないのです。

レンダーツリーは、HTMLのDOM + CSSのCSSOMで出来ていますね。

CSSOMが出来上がらないと、レンダーツリーは完成しないということです。

なので、初回のレンダリングの際にできるだけ早く表示されるように最適化する必要があります。

メディアクエリとメディアタイプはレンダリングブロックに大きく影響するので、注意しなくてはいけないのです。

JavaScriptは?

ここまでJavaScriptの話は一切出てきませんでしたが、JavaScriptもレンダリングブロックリソースになります。

HTMLファイルの解析が行われている時に、scriptに遭遇すると、DOMの作成は一旦中止されます。JavaScriptエンジンに制御が移り、JavaScriptの処理を行います。終わったらまた中止した場所に戻り、再開される仕組みです。

ということは、scriptタグの置き場所に要注意です。DOM作成前にJavaScriptが実行されても意味がありません。

(だからscriptタグは下(bodyタグの直上)に置かないといけないのか!と独り言)

CSSファイルとの関係はどうなっているかと言うと、JavaScriptはCSSOMが構築されるまで実行されません。

JavaScriptによって、DOM・CSSOMの依存関係が生まれてしまいました。

=ブラウザの遅延に大きく影響する。

これで、JavaScriptはパーサー(解析)ブロックであることがわかりました。

しかし例えば、スクリプトタグに、asyncを加えることでブラウザに

「JavaScriptの処理を順番通りに実行しないで、DOM構築を継続していいよ」

と伝えることができます。

<script src="app.js" async></script>

これが非同期ですね!こちらにより、パフォーマンス改善につながります。

パフォーマンスの分析

この一連の流れをCritical rendering path (CRP)と呼ぶそうです。

CRPを分析する方法として、ChromeのDevツールが使えます。

試しに、Airbnbのサイトを使って確認してみました。

DevツールのPerformanceから、回転矢印マークを押すと計測してくれます。

上記のスクショを見てみると、Scriptiong(JavaScriptの処理)に一番時間がかかっていますね。

Summary横のBottom-Upを見ると何が一番時間かかってるのかも見れたりします。

Airbnbさんのコンテンツが多くて自分なりに解析するのはちょっと難しかったですが、このようにしてレンダリング時間を確認できます。

ちなみに、記事の参考にしているこちらのサイトでは、DevツールはCRPの測定に最適でもないと言っています。

Lighthouse(Chromeの拡張機能)を使ってください、とのことなのでこちらも使ってみました。

拡張機能を有効にすると、DevツールにLighthouse項目が出てくるので、Generate reportをクリック。

すると解析が始まり(ちょっと時間かかる)こんな結果に。

結果表ではAccesibilityやSEOも見れて最高だし、下に画面のレコードも表示される(画像には写ってない)ので色々見やすいです。

ただ測定中にJavaScriptが実行されない謎の現象が起きて、パフォーマンスが19(!?)という結果になりました…

(さっきDevツールで測定したのと同じAirbnbのトップページ)

githubのissueに同じような問題に遭遇した方もいたり、また500以上のissueが報告されているのでまだまだ改善中なのかなと勝手に推測しました。

レンダリングの測定だけなら、Devツールでも充分なのではという感想です。

それか私のインターネット環境が悪かったのか。それも含めて計測してくれているのか….

(単なるエラーなのかわからない)

何にせよ、こういった便利ツールで画面表示を計測し、パフォーマンスの戦略を立てることが大事ということですね。

まとめ

Webのブラウザ表示を最適化することはCRPを最適化するということ。

レンダリングってこんなに奥深い処理をしているなんて、、と驚きですね。

ブラウザがWebを表示するのにこれだけの処理をしてくれているのかと。

今回の調査で、一つ一つの依存関係を理解して(できるだけなくし)、パフォーマンスを最適化することの大事さを理解できました。

参考にしたサイト

クリティカル レンダリング パス

How browser rendering works — behind the scenes