レンダリング
Parse(パース)
・HTMLとCSSを平行して解析
・DOM Tree(DOMツリー)とStyle Rules(スタイルルールズ)に変換
レンダリングエンジン
Safari:Webkit
Chrome:Blink
Firefox:Gecko
Edge:EdgeHTML
IE:Trident
Style(スタイル)
DOM TreeとStyle Rulesの紐づけ
どのスタイルがどの要素に適用されるのかをマッチング
複数個のスタイルが一致する要素に関しては、スタイル適用の優先順位に従って割り出す
Layout(レイアウト)
それぞれの要素の位置と大きさの計算
レイアウトの計算はRender Treeの上流から下流にかけて再帰的に行われる
画面の初期表示の際は一番上位のHTMLタグに相当するルートのレンダラーから計算が始まり、各階層を順番に処理する
画面更新をした場合、その要素と小要素、同じ階層の兄弟要素の再計算が行われる
最終的にLayout Tree(レイアウトツリー)が作成される
画面に表示する対象のものだけを含む
display: noneを適用した要素はLayoutツリー内には登録されない
Layoutツリー内に登録したい場合はvisibility: hiddenを使用
::before{content: ‘Text’}などの疑似要素はこの工程でLayoutの対象として含まれる
Global LayoutとIncremental Layout
Global Layoutはページ全体に関わるレイアウト(ブラウザの幅やフォントサイズ)が変更された場合に実行(重い)
Incremental Layoutは変更が限定的な場合(要素が追加された場合など)に実行(軽い)
Paint(ペイント)
要素の重なりを考慮して、順番に命令を作成する
モダンブラウザでは同時にLayer Tree(レイヤーツリー)を作成
Layerの分離は変更の際の計算量を少なくするために大変有効
Layerを分離せず描写を行った場合、変更があった際に他の要素との影響を考慮して多くの計算を行う必要がありる
レイヤーを分離しておくと、そのレイヤーのみ再計算を行えばよい
Layer Treeのレイヤーを分離する条件はz-indexとは関係ない
3Dトランスフォーム(transform: translateZ(0))やtransformを使用したアニメーションを検知した際にブラウザはLayerを分離する
will-changeを使用したアニメーションプロパティーの指定が合った場合にもLayerは分けられる
レイヤーの状態はChromeの開発ツールのLayerパネルで確認する事ができる
—
ここまでの処理がブラウザのMain Thread(メインスレッド)上でおこなわれる
Layer TreeとPaint RecordsはCompositor Thread(コンポジタースレッド)に渡され、Main Threadは開放される
—
Composite(コンポジット)
Compositor ThreadはPaint Recordsを元に各レイヤーのピクセル単位で色を当て込む(ラスタライズ)
それを4つのRaster Thread(ラスタースレッド)で並行して処理
Raster Threadでラスタライズ(色の当て込み)が完了した各レイヤーを合成レイヤーにまとめGPUに送り画面に表示
合成レイヤーの作成はViewport(画面内の領域)から優先
スクロールなどの画面処理を受け取った際に順次作成され、GPUに送られる
transform、opacityの適用もこの工程
Main Threadとは別のCompositor Threadで動く
Main ThreadでJavascriptが実行されても、処理の完了を待つ必要がない
pos: leftなどを使用したアニメーションではLayoutの工程から計算し直す必要があるためパフォーマンスが低下する
—
レンダリングとスレッド
—
Main Thread
Parse〜Paintまでを担当
レンダリングの処理以外にもJavascriptの実行を担当
Main Threadの負担をなるべく軽くすることが重要
Compositor Thread
レイヤーの合成が担当
Compositor ThreadはRaster Threadにレイヤーのラスタライズ(ビットマップ化)を依頼
Raster Threadによってラスタライズされた各レイヤーはCompositor Threadによって一枚のレイヤーに合成
前工程のPaint、Layoutが変更された場合(leftプロパティーによるアニメーションなどが行われた場合)はMain ThreadがComposite処理を一時的に代行
Raster Thread
レイヤーのラスタライズ(ビットマップ化)を行う
Raster Threadは4つあるので空いているスレッドに依頼がくる
GPU
画面への描写
transform、opacityを用いたアニメーションの場合はレイヤーはすでに分離されており、かつレイヤーのラスタライズも完了している
Compositor ThreadとGPU間のみでのやり取りとなり、Main Threadを待つ必要がなく、高速に処理することができる
—
ケース
—
Javascriptである要素の高さを変更した場合
大きさや位置の計算はLayoutの処理
Layoutに関わる変更が発生した場合、Styleからすべての工程を再計算する
Layoutに関わる変更は多くの計算を必要とし、パフォーマンスを下げる原因となる
また高さを変更した要素が、多くの子要素を持っている場合には、子要素の再計算も行う必要があるため注意が必要
Layoutの処理はMain Thread上で動いているので、他のJavascriptの処理に影響される
Layoutに関わる要素
height, width, padding, margin, top, right, left, bottom, box-shadowなど
Layoutに関わるアニメーションはなるべく行わない。代わりにTransformを使用する。
仮に行う必要がある場合は、なるべく子要素を減らし、will-changeの使用を検討する。
—
色を変更した場合
—
Layoutは関係ないのでスキップされて、Paint、Compositeが呼ばれる
Layoutの処理がない分、先程よりは処理時間は短くなりる
しかしMain Threadは使用されるので、処理が重くなる
opacityで代用できる方法を検討
Paintに関わる要素
background-color, background-image, border-color, colorなど
—
transformプロパティーでアニメーション
—
transformは一見、Layoutの操作に関係しそうですが、実際にはCompositeの処理
Main Threadに影響を受けることなく快適に処理することができる
Compositeに関わる要素
transform, opacity
レンダリングエンジンによってフローはそれぞれ異なる
Safariが使用しているWebkitではTransformプロパティーの変更でもLayoutから再計算する
CSS Trigersというサイトではプロパティーごとにどの処理が行われているのかを確認できる
[https://csstriggers.com/](https://csstriggers.com/)
—
AMP for Email
EmailにWebサイトのような動的な表示ができる
GOOD
サイトに遷移せずにリッチな表示ができる
・スライドショー
・フォームの設置
・レスポンシブ対応
BAD
使用できる環境が限定的
・Gmailのみ対応(2019/04/15時点)
・Googleに利用申請が必要
・実装にAMPの知識が必要
—
フロントエンドの興味深いネタがいろいろ載ってました
[https://leap-in.com/ja/category/blog/](https://leap-in.com/ja/category/blog/)
EmailにWebサイトのような動的な表示ができる「AMP for Email」
[https://leap-in.com/ja/how-to-implement-amp-for-email/](https://leap-in.com/ja/how-to-implement-amp-for-email/)
とか
ブラウザ レンダリングの仕組み
[https://leap-in.com/ja/lets-learn-how-to-browser-works/](https://leap-in.com/ja/lets-learn-how-to-browser-works/)
とか