本日覚えていって欲しいこと
- ブラウザはどのようにレンダリング(描画)をしているか
HTMLレンダリングエンジンとは
-
HTML(Webページの記述用言語)で書かれた文書を解釈し、記述された文書や画像などを描画するプログラムのこと。
-
ブラウザの主要な構成要素の1つ(青枠の部分)。
(引用:A Reference Architecture for Web Browsers)
以降、「レンダリングエンジン」と呼びますね。
レンダリングエンジンの仕事
- 要求されたコンテンツを画面上に表示すること
主要ブラウザのレンダリングエンジン
- Chrome - Blink
- Firefox - Gecko
- Safari - Webkit
- Internet Explorer - Trident
- Microsoft Edge - EdgeHTML
レンダリングのプロセス
- HTML・CSSを解析する (Parser)
- DOMとCSSOMを組み合わせてレンダーツリーを構築する
- CSSの詳細度を計算して優先順位を決める (Cascade)
- 位置やサイズを決定する (Layout)
- 各レイヤーの描画処理を行う (Paint)
- 各レイヤーを重ね合せる (Composite)
(引用:Houdini: Maybe The Most Exciting Development In CSS You’ve Never Heard Of)
1-1.DOMツリー
- DOM = Document Object Model
こういう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-2.CSSOMツリー
- CSSOM = CSS Object Model
こういうCSSがあった時の、
body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }
これ。
(引用: オブジェクト モデルの構築)
この図では独自CSS(自分が書いたCSS)しかツリー表示されてないですが、実際には各ブラウザが持っている「ユーザーエージェントスタイル」も存在します。
スタイルを何も指定してなかったら各ブラウザの「ユーザーエージェントスタイル」が引き継がれるのだけど、そのブラウザ間の差異を均一にするためにreset.css、Normalize.css、sanitize.cssとかがあるんだよ〜。
2.レンダーツリー
- DOMツリーとCSSOMツリーを組み合わせたもの。
(引用: レンダリング ツリーの構築、レイアウト、ペイント)
- 一部のノード(スクリプトタグ、メタタグなど)はレンダリング出力に反映されないので省略される
- CSSによって非表示に設定されているノードも、同様にレンダーツリーから省略される
上の図で
display: none
が指定されているspan
ノードはレンダーツリーで省略されます。
3.Cascade
- 表示されるノードごとに、一致する適切なCSSOMルールを見つけて正しいカスケード順序(Cascade Order)で適用する
- コンテンツおよび計算済みスタイルを含めて、表示されるノードを出力する
ここで、画面上に表示可能なすべてのコンテンツと、そのスタイル情報の両方を含むレンダーツリーが出力されました。
「表示されるノードと、そのノードの計算済みのスタイルが分かった」状態です。
CSS) カスケード処理と継承
「CSS Cascading and Inheritance Level 3」より。
カスケード処理は以下の優先順位で処理される。
- Origin and Importance (出自と重要性) ← 滝口(カスケードの上)
- Scope(スコープ)
- Specificity(詳細度)
- Order of Appearance(出現順序) ← 滝壺(カスケードの下)
細かいことは置いておいて、下記で覚えておけばおk。
!important
- style属性
- セレクタの詳細度
- コードの中での出現順序
CSS) 詳細度
「Selectors Level 3」より。
詳細度の計算方法。
- IDセレクタの数 (=a)
- classセレクタ・属性セレクタ・擬似クラスの数 (=b)
- タイプセレクタ(要素セレクタ)・擬似要素の数 (=c)
- ユニバーサルセレクタは無視する
- 否定擬似クラス(
:not(X)
)の中のセレクタは他のセレクタと同様にカウントされるが、否定(:not
)自体は擬似クラスとしてはカウントされない。 - a-b-cを number system with a large base (ナントカ進数、だと思われる)で結合し、詳細度を与える。
詳細度の計算例
* /* a=0 b=0 c=0 -> specificity = 0 */
LI /* a=0 b=0 c=1 -> specificity = 1 */
UL LI /* a=0 b=0 c=2 -> specificity = 2 */
UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */
LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */
#x34y /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
別に計算式までは覚えなくていい。や、覚えても良いけども。
4.Layout
- 端末のビューポート内でのノードの正確な位置とサイズ(どのくらいのスペースが必要か、画面のどこにあるか)を特定する
- WebkitではLayout、GeckoではReflowと呼ばれる
こういうHTMLがあった時に、
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Critial Path: Hello world!</title>
</head>
<body>
<div style="width: 50%">
<div style="width: 50%">Hello world!</div>
</div>
</body>
</html>
こういう計算をする。
(引用: レンダリング ツリーの構築、レイアウト、ペイント)
大きさと配置場所の計算やね!
CSS) 配置(要素を並べる)
「CSS Positioned Layout Module Level 3」より。
CSSのボックスは下記3つの位置決定スキームに沿って配列される。
- 通常フロー:ボックスを順々に並べる。
- フロート(浮動体):まずは通常フローに則ってレイアウトされてから、通常フローから外され、可能な限り左(または右)へ寄せられる。clearされない限り、続くボックスは浮動体の脇に浮動していく。
- 絶対位置決め:ボックスは、通常フローからまるごと除去された上で(続くボックスは、ボックスが元から無かったかのようにレイアウトされる)、包含ブロックの中で指定された位置に配置される。
とりあえずCSSで配置をするときにこういう概念と挙動があることを覚えておけばおk。
5.Paint
- ピクセルを書き込む処理
- レンダーツリー内の各ノードを画面上の実際のピクセルに変換する
- テキスト・色・イメージ・線・影などの、実質上、要素の視覚的な部分すべての描画が行われる
- 一般的にレイヤーと呼ばれる複数の面で行われる
- WebkitではPainting、GeckoではRepaintと呼ばれる
色とかつけてくれるんやね!
6.Composite
- 潜在的に複数のレイヤーに描かれているページのパーツを、正しい順序で画面に描画する処理
- 順序を間違えると要素が誤った要素の上に表示される場合があるため、重なり合う要素の場合はこれが特に重要
z-indexとかz-indexとかz-indexとかな...!!
CSS)配置(要素を重ねる)
CSS Positioned Layout Module Level 3 より。
- CSSにおいて、あらゆるボックスは、水平・垂直・z軸の3次元の位置を持つ
-
z-index
プロパティでスタックレベルを明示し、同じスタック文脈内での要素の重なり順を指定する
スタック文脈:ある条件を満たした要素によって形成される階層構造(文脈)のこと
スタックレベル:同一のスタック文脈内での重なり順
(引用:CSS再入門第4回 z-index再入門 1 | CodeGrid)
LayoutとPaintは繰り返し行われる
- ローディング中、完了後に関わらず、スタイルの変更、JavaScriptによる動的な処理、ユーザー操作によって変更が生じた場合にLayoutやPaintingは発生する
- 必然的にCompositeも発生する
// 余白を変更する
document.body.style.padding = '30px'; // Layout と Paint が発生
// フォント色を変更する
document.body.style.color = 'blue'; // Paint のみ発生
// ul以下にliを追加する DOMツリー、レンダーツリー、Layout、Paintの各イベントが発生
const ul = document.querySelector('ul');
const li = document.createElement('li');
li.textContent = 'JavaScriptで挿入したli要素';
ul.appendChild(li);
パフォーマンスに大きな影響を与えるので、ここら辺の理解は大事です。ブラウザに優しいJavaScriptについて詳しくは浅井兄やんに聞いてみればいいんじゃないかな!
次回予告
ブラウザがどのようにレンダリングをしているか、なんとなくご理解いただけたでしょうか?
表示の高速化、ひいてはユーザーのより良い使い心地のために、ここら辺を理解しておくことはとても大事です。
次回は、CSSを破綻させないための人類の叡智の結晶である、設計思想や命名規則について勉強しましょ〜。