ブラウザのレンダリング:テキストが画像になるまで

画面が描かれるのは魔法ではない

フロントエンド開発(Vue.js)を初めて始めたとき、私はブラウザをただ「コードを見せる額縁」くらいだけ考えた。

を書くと四角が出て、color: redを書くと赤になるのが当然だった。

しかし、実務でアニメーションがガラガラしたり、スクロールを下したときに画面が突き破られる現象(Jank)を経験しながら、私の考えは変わった。 「なぜ同じコードを編んでいるのにクロムでは柔らかく、Internet Explorer(IE)では途切れるのか?」 「なぜJavaScriptでスタイルを少し変えたのにCPUが上がるのか?」

わかると、ブラウザは単なる額縁ではありませんでした。ブラウザは、私たちが送ったテキスト(HTML / CSS)を解釈し、ピクセル一つ一つを数学的に計算して撮る巨大な「画家(Painter)」であり「建築家」だった。

過去の時間、私たちは大まかなネットワーク道路を通ってデータを無事に出荷しました。今回は到着したデータボックス(パケット)を開けて、ブラウザがどのように画面という絵を描くのか調べてみよう。これがRe:Booting CS基礎シリーズの最後の話です。

ブラウザはコードを読み、構築、塗りつぶす建築現場です。

到着した貨物、組み立てを開始する

私たちの「デジタル物流センター」の世界観で、物事(HTMLファイル)が顧客の家(ブラウザ)に到着しました。しかし到着したのは完成品ではなく「組立説明書」だ。ブラウザエンジン(レンダリングエンジン)という作業チームはこのマニュアルを見てすぐに組み立てに入る。このプロセスをレンダリングパイプラインと呼びます。

ステップ1: 設計図の分析 (Parsing & DOM Tree)

最初に到着したHTMLテキストを読み、「スケルトン」を作成します。

  • <html>は根(Root)、<body>は幹、<div>は枝…
  • このようにツリー(Tree)構造で組み立てたものをDOM(Document Object Model)と呼ぶ。JavaScriptが後からこのスケルトンに触れられるようにするAPIでもある。

ステップ2:インテリアデザイン(CSSOM Tree)

次にCSSファイルを読んで「スタイルルール」を作成します。

  • 「すべてのdivは赤」「クラスがboxのやつはサイズ100px」
  • これをCSSOM(CSS Object Model)と呼ぶ。

ステップ3: 作業指示書の作成 (Render Tree)

今、スケルトン(DOM)とデザイン(CSSOM)を組み合わせます。ここで重要なのは、「実際に画面に見えるもの」だけを選び出すということです。

  • display: none属性を持つ要素は?画面に表示されないものなので、レンダーツリーから除外される。(スペースも占有しない)
  • 一方、visibility: hiddenは?見えないがスペースは占有するので、レンダーツリーに含まれる。
レンダーツリーは、「本当に描かれる人たち」だけを集めた最終的なリストです。

[Code Verification]リフロー(Reflow)とリペイント(Repaint)

これは本当に重要なステップです。性能最適化の核心がここにある。レンダーツリーが作成されると、ブラウザは2つの重い作業を行います。

  1. レイアウト(Layout)/ リフロー(Reflow):各要素を「どこに、どんなサイズで」配置するかを数学的に計算する。(建築設計)
  2. ペイント(Paint)/ リペイント(Repaint):計算された位置に実際に「色を塗る」。(塗装作業)

コードでこのコストの違いを感じましょう。

const box = document.getElementById('box');

// Case 1: レイアウト(Reflow)を引き起こすコード(高コスト!)
// サイズや位置を変えると、周囲の要素の位置まで全部再計算される。
box.style.width = '200px'; 
box.style.height = '200px';
box.style.margin = '20px';

// Case 2: ペイント(Repaint)だけを引き起こすコード(比較的安い)
// 位置はそのままで、色だけ変える。計算なしで塗り直しだけで済む。
box.style.backgroundColor = 'blue';
box.style.color = 'white';
box.style.visibility = 'hidden';

分析:

  • widthの変更:建物のサイズを変える工事だ。隣の建物も押し出され、さらにその隣の建物も押し出される。ブラウザは全体の計算をもう一度やり直さなければならない。(Reflowが発生 -> パフォーマンス低下の主犯)
  • colorの変更:建物のサイズはそのままで、ペンキを塗り直すだけだ。計算し直す必要はない。(Repaintが発生 -> 速い)

実務では、「アニメーションがうるさい」は、ほとんどの場合、width、left、topなどのレイアウト属性にリアルタイムで触れたために発生します。このような場合は、transformのような属性を使ってレイアウト計算をスキップするテクニックが必要です。

実践的なアドバイス:ブラウザを悩ませないでください

学部の時はこんなことを知らなかったので、JavaScriptでDOMを雑誌で操作した。 for ドアを回しながら要素一つ一つの大きさを変え、スタイルを塗った。ブラウザの立場では、1秒に数十回ずつ建物を壊して再建する拷問に遭ったわけだ。

パフォーマンスを守るためのヒント:

  1. DOM操作はまとめて一度に:スタイルを一つずつ変えるのではなく、classをあらかじめ用意しておき、classNameだけを一度で切り替えよう。
  2. アニメーションはGPUに任せる:left、topの代わりにtransform: translate()を使えば、レイアウトの段階をスキップしてGPUが処理してくれる。
  3. 隠すときの違い:完全になくしてしまうならdisplay: none(レンダーツリーから除外)、場所だけ空けておくならvisibility: hidden(レンダーツリーに含まれる)と使い分けよう。
位置を変更することは、色を変更するよりもはるかに高価な作業です。

シリーズ1の終了:再起動した私のCS

この記事の最後に、 [Re: Booting] CS基礎シリーズが停止しました。

私たちは長い旅をしました。

  1. 言語(Language):人が書いたコードが機械語に翻訳され(ビルド)、
  2. メモリ(Memory):スタックとヒープという部屋に入居し、
  3. プロセス(OS):スレッドという分身の術を使ってCPUを分け合い、
  4. ネットワーク(Network):パケットに分割されて荒れた道路を走り抜けた後、
  5. レンダリング(Rendering):ブラウザという画家に出会い、ようやく私たちの目の前に姿を現した。

最初はただ就職のために月々覚えた知識だった。しかし、実務のエラーとぶつかり、再び覗いたCS(コンピュータ工学)は、死んでいる文字ではなく、私のコードを支える硬い地盤だった。

これで基礎工事は終わった。硬くなった地盤の上に本格的に自分だけの城を築く時間だ。次のシリーズ[Monolith Builder]では、私が実務で経験したSpring BootとVue.jsを活用したWebアプリケーションビルダーを扱う予定だ。 「理論」が「実践」になるその過程を期待してほしい。

コメントする