こんにちは!日夜、Webブラウザという「世界で最も身近なモンスターマシン」と向き合っているフロントエンド・アーキテクトです。
日々のコーディングの中で、「CSSでアニメーションを作ったら、スマホでなんだか動きがカクカクするなぁ…」とか、「JavaScriptで要素を動かしたら画面が一瞬チラついた!」なんて経験はありませんか?
「自分のコードのどこが悪いんだろう…」と落ち込まなくても大丈夫です。それは誰もが通る道ですし、何よりブラウザの裏側で何が起きているかを知るだけで、その悩みは一瞬で、しかも驚くほどスッキリと解決します。
今日は、ブラウザがHTMLやCSSを受け取ってから、実際に私たちのディスプレイに美しい画面を描き出すまでの裏舞台――「ブラウザレンダリングパイプライン」の世界へ、みなさんをご案内します。難しい数式や専門用語は、身近な例え話でぜんぶ優しく解きほぐしていきますので、どうぞリラックスしてコーヒーでも飲みながら読み進めてみてくださいね。
—
画面が映るまでの「5つのステップ」
ブラウザが画面を描くプロセスは、まるで「1本の映画や演劇を作り上げる舞台裏」にそっくりです。
ブラウザは、私たちが書いたコードを元に、次の5つのステップをものすごいスピードで駆け抜けています。
1. Recalculate Style(スタイルの再計算):役者の衣装を決める
2. Layout(レイアウト):舞台の立ち位置を決める
3. Update Layer Tree(レイヤーツリーの更新):背景の「手前と奥」を整理する
4. Paint(ペイント):小道具や衣装に色を塗る
5. Composite(コンポジット・合成):カメラで1枚の映像に合成する
この5つのステップを、一つずつ丁寧に覗いていきましょう!
—
Step 1: Recalculate Style(スタイルの再計算)
〜 役者(DOM)に衣装(CSS)を着せる時間 〜
まずブラウザは、HTMLから作った「骨組み(DOM)」と、CSSから作った「ルールの束(CSSOM)」を机の上に広げます。
/ CSS(ルール) /
.btn { background: gray; }
.btn.active { background: blue; }
ブラウザはこれらを見比べて、「ふむふむ、この『送信する』というボタン(要素)は、いま `active` クラスがついているから、背景色はグレーじゃなくてブルーにするんだな」という計算を行います。
これがRecalculate Style(スタイルの再計算)です。
すべての要素に対して、「最終的にどのデザインを適用するか」を確定させる、いわば役者たちに衣装を着せるフェーズですね。
—
Step 2: Layout(レイアウト)
〜 舞台の上での「立ち位置」と「サイズ」を測る 〜
衣装が決まったら、次は「誰が、どこに、どれくらいの大きさで立つか」を決めなければいけません。
- 「このボタンの横幅は何ピクセル?」
- 「画面の端から何ピクセル空けて配置する?」
- 「文字が2行になったから、ボタンの高さも少し広げなきゃ!」
ブラウザは画面の上から下へ向かって、要素同士が押し合ったり、はみ出したりしないように、ミリ単位(ピクセル単位)で計算していきます。これをLayout(レイアウト)、あるいは別の言葉でReflow(リフロー:再配置)と呼びます。
実を言うと、このステップはブラウザにとって非常にエネルギーを使う、重労働な作業なんです。
なぜなら、1つの要素の大きさが変わると、「じゃあ俺はどこに避ければいいの!?」と周りの要素すべてに影響が及ぶ(ドミノ倒しのように計算が連鎖する)からです。
—
Step 3: Update Layer Tree(レイヤーツリーの更新)
〜 舞台の「手前」と「奥」のレイヤー(層)を分ける 〜
現代のWebサイトは、平らな絵ではありません。
スクロールしてもついてくる「ヘッダー」や、画面の手前にふわっと浮き出る「ポップアップ(モーダル)」など、奥行き(重ね合わせ)がありますよね。
ブラウザは、画面をスムーズに動かすために、「この要素はあとで動くかもしれないから、別々の透明なシート(レイヤー)に分けておこう」という判断をします。アニメのセル画をイメージすると分かりやすいかもしれません。
- 背景のレイヤー
- スクロールするコンテンツのレイヤー
- 手前に浮かぶポップアップのレイヤー
これらを整理整頓して、重ね合わせの順番を決めるのがUpdate Layer Tree(レイヤーツリーの更新)です。
—
Step 4: Paint(ペイント)
〜 キャンバスに、色や文字を「描き写す」 〜
「よし、配置もレイヤーも決まった!じゃあ色を塗ろう!」……となりそうですが、実はこのペイントフェーズでは、まだ画面に直接ペンキは塗りません。
ブラウザがここでやるのは、「描き方の指示書(Display List)」を作ることです。
「まず(0, 0)の位置に青い四角を描いて、その中に白い文字で『送信する』と書き、角を丸くする…」といった、プラモデルの説明書のような手順書を作成します。
この指示書を作ること、そして実際にピクセルデータ(画像データ)に変換する一連の処理をPaint(ペイント)、またはRasterize(ラスタライズ)と呼びます。
—
Step 5: Composite(コンポジット・合成)
〜 分割されたレイヤーを、超高速で1枚に合成して完成! 〜
さあ、いよいよフィナーレです!
これまでのステップで、バラバラの「レイヤー(層)」に、それぞれの「ペイント指示書」を使って絵が描かれました。
最後は、このバラバラのレイヤーを、「上から順番に重ね合わせて、1枚の完成された画面にする」作業を行います。これがComposite(コンポジット:合成)です。
ここで大活躍するのが、パソコンやスマホに搭載されている「GPU(グラフィックス・プロセッサ)」という、画像処理の専門家です。
GPUは、すでに描かれたレイヤーを「スライドさせる(移動)」「引き伸ばす(拡大縮小)」「薄くする(不透明度)」といった処理を、目にも留まらぬ超高速で行うのが大得意です。
そのため、このコンポジット段階だけで処理が済むアニメーションは、信じられないほど滑らかに(ヌルヌルに)動くのです!
—
現場のリアル:なぜアニメーションがカクつくのか?
ここで、私たちフロントエンド開発者がよく直面する「カクつき(フレームドロップ)」の正体をお話しします。
ブラウザは、1秒間に60回(最近の高価なスマホやディスプレイでは120回!)も画面を書き換えています。
つまり、1回分の書き換えにかけられる時間は、わずか「16.6ミリ秒(1秒 ÷ 60回)」しかありません。この短い時間の中で、先ほどの5つのステップを処理しなければならないのです。
もし、JavaScriptやCSSで「要素の幅(`width`)」をアニメーションさせたらどうなるでしょうか?
【width を変更したとき】
[Style] ➔ [Layout (重い!)] ➔ [Layer] ➔ [Paint] ➔ [Composite]
`width` が変わると、周りの要素の立ち位置も変わるため、最悪の重労働である「Layout」からやり直さなければなりません。
16.6ミリ秒の制限時間を超えてしまい、処理が間に合わず、画面が「カクッ」と飛んでしまうのです。これが「リフロー」によるパフォーマンス低下の正体です。
一方で、「位置(`transform: translateX()`)」や「透明度(`opacity`)」だけを変化させるとどうでしょう?
【transform や opacity を変更したとき】
[Style] ➔ [Composite (超軽い!)]
なんと、LayoutもPaintもスキップして、最後の「Composite」だけで処理が終わります!
すでに描いてあるレイヤーを、GPUがシャッと動かすだけなので、16.6ミリ秒なんて余裕でクリア。スマホでも吸い付くような、滑らかなアニメーションが実現できるのです。
—
実践:滑らかに動くアニメーションを作ってみよう!
百聞は一見にしかず、です。
実際に「悪い例(Layoutを発生させる)」と「良い例(Compositeだけで処理する)」を比較できるコードを用意しました。
以下のコードをHTMLファイルとして保存し、ブラウザで開いてみてください。実際にボタンを押して、動きの滑らかさや、ブラウザのデベロッパーツールで裏側の動きを観察してみましょう!
ブラウザの優しさを感じるアニメーション比較
下のボタンを押して、2つのボックスの動きを見比べてみましょう。
一見同じように動きますが、赤色は「立ち位置の再計算(Layout)」を毎回行い、
緑色は「画像の合成(Composite)」だけでスイスイ動いています。
❌ Layoutを発生させる箱
⭕ Compositeだけで動く箱
—
まとめ:ブラウザの気持ちに寄り添う、ということ
いかがでしたでしょうか?
一見難しそうに見える「ブラウザレンダリングパイプライン」ですが、その本質は「ブラウザにいかに無駄な計算をさせずに、得意な仕事を割り振るか」という、思いやりの心にあります。
- Layout(リフロー)を伴うプロパティ(`width`, `height`, `margin`, `padding`, `top`, `left` など)を変更するときは、「ブラウザに模様替えのやり直しをさせているんだな」と意識してみましょう。
- Composite(合成)だけで済むプロパティ(`transform`, `opacity`)を積極的に使うことで、ブラウザも、そして何よりWebサイトを訪れるユーザーも、みんなが幸せになります。
最初からすべてを完璧に暗記する必要はありません。
「そういえば、昔あのアドバイスで『レイヤーをGPUにスライドさせるのが一番軽い』って言ってたな」と、いつかパフォーマンスに困ったときに、フッと思い出していただければ十分です。
大丈夫、一歩ずつ進んでいきましょう。あなたの書くコードは、この知識を得た今日から、もっと優しく、もっと速くなります!
またフロントエンドの深い世界でお会いしましょう。ハッピー・コーディング!

コメント