1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

前回の記事の範囲まででDOMツリーが構築された。が、一つ目の記事でも書いたようにDOMと画面描画は完全に独立している。

ブラウザは、DOMツリーを元に色々な段階経て、最終的にピクセルを画面に描画する。
この色々な段階をレンダリングパイプラインと呼ぶ。

てことでレンダリングパイプラインを学ぶ!

レンダリングとは

コンピュータが持つ数値データや抽象的な情報を、人間が視覚的に理解できる画像や映像、音声などに変換・生成する処理のこと

レンダリングパイプラインと呼ばれる理由

工場のライン作業みたいに、各段階を順番に通って完成するから

DOM => CSSOM => Render Tree => Layout => Paint => Composite
 ↓       ↓          ↓            ↓         ↓         ↓
原料     加工      組み立て        配置      塗装       完成

レンダリングパイプラインの全体像

DOM => CSSOM => Render Tree => Layout => Paint => Composite
         ①           ②           ③        ④     ⑤

各段階で、異なる処理が行われる。

①CSSOMの構築

DOM = HTMLの構造をツリーにしたもの
CSSOM = CSSの構造をツリーにしたもの(CSS Object Model)

ブラウザはHTMLをパースしながら同時にCSSも解析してCSSOMを作る。

CSSファイル
body { font-size: 16px; }
.container { width: 100%; }
.container p { color: blue; }
CSSOM
body
├─ font-size: 16px
└─ .container
   ├─ width: 100%
   └─ p
      └─ color: blue

CSSの読み込みが終わるまでレンダリングは始まらない。

なぜか?
=> 一瞬スタイルなしで表示される(FOUC)を防ぐため
なのでCSSは<head>内でできるだけ早く読み込む方がいい。

JavaScriptからCSSOMにアクセスできる
// スタイルシートの取得
const styleSheets = document.styleSheets;

// 特定のルールへのアクセス
const rules = styleSheets[0].cssRules;
console.log(rules[0].selectorText); // "body"
console.log(rules[0].style.fontSize); // "16px"

②レンダーツリー(Render Tree)の構築

レンダーツリー = DOM + CSSOM を合体させたもの
ただし、「画面に表示されるものだけ」 がレンダーツリーに含まれる。

P1:レンダーツリーに含まれない要素
以下の要素は「画面に表示されるものでない」のでレンダーツリーに含まれない。

  • <head>とその内容(<title><meta><script>など)
  • display: noneが指定された要素
  • <script>タグ
  • <style>タグ

P2:display: noneとvisibility: hiddenの違い

display: noneとvisibility: hiddenの違い
<div style="display: none;">レンダーツリーに含まれない</div>
<div style="visibility: hidden;">レンダーツリーに含まれる</div>
  • display: none:レンダーツリーに含まれない&レイアウトに影響しない。
  • visibility: hidden:レンダーツリーに含まれる&レイアウト上の空間を占める。

P3:擬似要素
::before::afterなどの擬似要素は、DOMには存在しないがレンダーツリーには含まれる。

.item::before {
  content: "• ";
}

この擬似要素はDOMノードとしては存在しないが、レンダーツリーではレンダーオブジェクトとして存在する。

③レイアウト(Layout / Reflow)

レイアウト(Layout / Reflow) = レンダーツリーが構築された後、各要素の正確な位置とサイズを計算する処理のこと。

P1:レイアウトで計算されるもの

  • 要素の幅と高さ
  • 要素の位置(x, y座標)
  • マージン、パディング、ボーダーの寸法
  • フロート、フレックスボックス、グリッドによる配置

P2:ボックスモデル

すべての要素はボックスとして扱われる。

┌─────────────────────────────────┐ 
│           margin                │
│  ┌───────────────────────────┐  │
│  │        border             │  │
│  │  ┌─────────────────────┐  │  │
│  │  │      padding        │  │  │
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │    content    │  │  │  │
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
├─────────────────────────────────┤
│           margin                │
│  ┌───────────────────────────┐  │
│  │        border             │  │
│  │  ┌─────────────────────┐  │  │
│  │  │      padding        │  │  │
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │    content    │  │  │  │
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘

④ペイント(Paint / Repaint)

ペイント(Paint / Repaint) = レイアウトが完了した後、実際にピクセルを描く(色をつける)

P1:ペイント順序

背景色 => 背景画像 => ボーダー => 子要素 => アウトライン

※なのでbackground は border より後ろに来ない

P2:z-indexとスタッキングコンテキスト

要素の重なり順は、「z-indexで決まる」のではなく「スタッキングコンテキストによって決まる」 と考える。(何もない場合普通はHTMLの後に書いた方が上)

.parent {
  position: relative;
  z-index: 1; /* 「新しいスタッキングコンテキストを作成」と考える。 */
}
z-index: 9999 なのに上に来ない! → 親が負けてるから
parent-a (z-index: 1)
└─ child-a (z-index: 9999)  ← どんなに大きくても

parent-b (z-index: 2)       ← 親が勝ってるので
└─ child-b (z-index: 1)     ← こっちが上に来る
子は親のスタッキングコンテキストの中でしか戦えない。

スタッキングコンテキストを作成する条件の一部

  • positionrelativeabsolutefixedstickyで、z-indexauto以外
  • opacityが1未満
  • transformnone以外
  • filternone以外
  • will-changeで特定のプロパティを指定

メモ⬇️:スタッキングコンテキストについてのわかりやすい記事
https://ics.media/entry/200609/

⑤コンポジット(Composite)

コンポジット(Composite) = レイヤーを合成して最終的な画面を作る段階.。
各レイヤーを個別に描画して最後にGPU(画像処理が得意&並行処理)を使って合成する。

レイヤーが作成される条件

以下の条件を満たす要素はレイヤーになる。(これは日本語あってるのか)

  • transformプロパティが使用されている
  • opacityが1未満
  • will-changeプロパティが指定されている
  • <video><canvas>要素
  • position: fixed
  • 3D変換(transform: translate3d()など)
┌─────────────────────┐
│  ヘッダー(固定)      │  ← スクロールしても動かない
├─────────────────────┤
│                     │
│  コンテンツ          │  ← スクロールで動く
│  コンテンツ          │
│  コンテンツ          │
│                     │
├─────────────────────┤
│  フッター(固定)     │  ← スクロールしても動かない
└─────────────────────┘
CSS
.header {
  position: fixed;  /* 固定 => レイヤー誕生 */
  top: 0;
}
.footer {
  position: fixed;  /* 固定 => レイヤー誕生 */
  bottom: 0;
}
ブラウザが作るレイヤー
レイヤー3: ヘッダー(固定)
レイヤー2: フッター(固定)
レイヤー1: コンテンツ(スクロールする部分)

↓ 合成 = コンポジット(Composite)

画面に表示

レイヤーの意義 = 再計算、再描画される箇所を減らすことができる

補足:レンダリングパイプラインの再実行

DOMやCSSが変更されるとパイプラインの一部または全部が再実行される。

Reflow(レイアウトの再計算)が発生する変更

  • 要素の追加・削除
  • 要素のサイズ変更(width、height、padding、margin、border)
  • フォントサイズの変更
  • テキスト内容の変更
  • ウィンドウのリサイズ
  • スクロール位置の取得

Repaint(ペイントからの再実行)のみが発生する変更

  • 背景色の変更
  • テキスト色の変更
  • 影の変更
  • 可視性の変更(visibility)

Compositeのみ発生する変更

  • transformによる変形
  • opacityの変更

まとめ(感想)

知らないって怖いなと思った。

TODOクリティカルレンダリングパス勉強する
https://web.dev/learn/performance/understanding-the-critical-path?hl=ja

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?