TL

ブラウザのレンダリングの仕組み

受け取った HTML と CSS を、ブラウザが DOM・CSSOM →レンダーツリー→レイアウト→ペイント→合成と段階的に処理して、最終的にピクセルとして画面に描き出すまでの流れ。

中級ブラウザレンダリングDOMパフォーマンス最終更新: 2026-06-04
TL;DR要点だけ先に
  • 1.ブラウザは HTML→DOM、CSS→CSSOM を作り、両者を合わせたレンダーツリーから レイアウト→ペイント→合成 の順で画面を描く(クリティカルレンダリングパス)。
  • 2.位置やサイズが変わると レイアウトからやり直す“リフロー”、見た目だけなら“リペイント”。リフローは重いので避け、できれば transform/opacity の合成だけで動かす。
  • 3.`<script>` は標準でパースを止める。外部 JS は基本 defer、依存しない計測系などは async。CSS は早く、JS は遅らせるのが高速化の基本。

全体の流れ

最初の表示(ファーストビュー)までに、ブラウザは大きく5つの工程を踏みます。

  1. パース → DOM:HTML を解析し、要素の親子関係を表すツリー(DOM)を作る。
  2. パース → CSSOM:CSS を解析し、各要素にどのスタイルが効くかのツリー(CSSOM)を作る。
  3. レンダーツリー構築:DOM と CSSOM を合わせ、実際に画面に出る要素だけを集めたツリーを作る。
  4. レイアウト(リフロー):各要素の位置と大きさを、ビューポートを基準に計算する。
  5. ペイント → 合成:ピクセルを塗り(ペイント)、複数のレイヤーを重ね合わせて(合成)最終画面を作る。

ポイントは、この順番は基本的に飛ばせないこと。位置が決まっていない要素を塗ることはできないので、レイアウトの前にペイントは来ません。

DOM:HTML から作る要素のツリー

ブラウザは HTML を上から読み(パースし)、<html> を頂点とする親子関係のツリーDOM(Document Object Model) に変換します。タグの開閉を解釈して入れ子構造を組み立て、文字はテキストノードになります。

<body>
  <h1>Hello</h1>
  <p>世界よ <strong>こんにちは</strong></p>
</body>

この HTML は「body の下に h1 と p、p の下にテキストと strong」という木構造の DOM になります。JavaScript から document.querySelector などで触れるのは、この DOM です。

HTML(文字)と DOM(ツリー)は別物

<div>...</div> というテキストが HTML、それをブラウザが解釈して作るメモリ上のオブジェクトツリーが DOM です。JS で element.textContent を書き換えると変わるのは DOM のほうで、サーバ上の元 HTML ファイルは変わりません。詳しくは DOM の解説へ。

CSSOM:CSS から作るスタイルのツリー

並行して、ブラウザは CSS を解析して CSSOM(CSS Object Model) を作ります。これは「どの要素に、最終的にどんなスタイルが当たるか」を計算したツリーです。継承(親の color を子が引き継ぐ)や、詳細度(#id.class のどちらが勝つか)の解決もここで行われます。

CSS は レンダリングをブロックするリソースです。スタイルが未確定のまま描画すると、いわゆる「スタイル崩れの一瞬(FOUC)」が起きるため、ブラウザは CSSOM が出来上がるまで描画を待ちます。だから CSS はできるだけ早く・小さく届けるのが鉄則です。

レンダーツリー:実際に“描かれる”ものだけ

DOM と CSSOM を合わせて レンダーツリー を作ります。重要なのは、DOM とレンダーツリーは一致しないことです。

  • display: none の要素は レンダーツリーに載らない(場所も取らず、描かれない)。
  • <head><script>、メタ情報など画面に出ないノードも載らない。
  • visibility: hidden載る(見えないが場所は取る)点が display: none との違い。
指定レンダーツリー場所(レイアウト)見た目
display: none載らない取らない消える
visibility: hidden載る取る見えない(空白が残る)
opacity: 0載る取る透明(クリックは効く)

レイアウト → ペイント → 合成

レンダーツリーが出来たら、いよいよ画面化です。ここが本記事の心臓部です。

レイアウト(別名:リフロー)

各要素が ビューポート上のどこに・どれだけの大きさで収まるかを計算します。width: 50% のような相対値を実際のピクセルに直し、ボックスの座標を確定させる工程です。ウィンドウ幅が変わると全体を計算し直すため、ここは重い処理になりがちです。

ペイント(ラスタライズ)

確定した各ボックスを、実際のピクセルに塗ります。文字・色・影・枠線・画像などを、レイヤーというキャンバスに描き込む工程です。

合成(コンポジット)

ページは1枚絵ではなく、複数のレイヤーに分かれて描かれることがあります(position: fixed の要素や、transform を持つ要素などが別レイヤーになりやすい)。それらを正しい重なり順で合成して、最終的に画面へ出します。この合成は GPU が担当することが多く、非常に高速です。

“合成だけ”で動かすと速い理由

transformopacity の変化は、レイアウトもペイントもやり直さず、合成のステップだけで済むことが多いです。アニメーションを left/top/width ではなく transform: translate() / scale() で行うと、毎フレームのリフロー・リペイントを避けられ、滑らか(60fps)になりやすい——これが「transform で動かせ」と言われる理由です。

リフロー と リペイント

一度表示した後も、画面は更新され続けます。何が変わったかによって、やり直す工程が変わります。

  • リフロー(reflow):要素の位置・サイズが変わったとき。レイアウトからやり直すので最も重い。1要素の変更が、周りや子孫の再計算を連鎖的に引き起こすこともある。
  • リペイント(repaint):位置は変わらず見た目(色・背景・影など)だけ変わったとき。レイアウトは飛ばしてペイントから。
  • 合成のみtransform/opacity の変化など。レイアウトもペイントも飛ばせる。最も軽い
きっかけ(例)発生する処理コスト
width / height / 要素の追加削除 / フォント変更リフロー → リペイント → 合成高い
color / background / box-shadowリペイント → 合成
transform / opacity合成のみ低い
レイアウトスラッシング(強制同期レイアウト)

JS で「スタイルを書き換える → その直後にレイアウト値を読む」をループで交互にやると、ブラウザは値を正しく返すために毎回その場でリフローを強制されます(強制同期レイアウト)。これが積み重なると一気にカクつきます。対策は、読み取り(offsetWidth 等)をまとめてから、書き込み(スタイル変更)をまとめること。

// ❌ 読み書きが交互 → 毎回リフローを強制(レイアウトスラッシング)
for (const el of items) {
  el.style.width = el.offsetWidth + 10 + 'px'; // 書く直前に読む→強制リフロー
}

// ✅ 先に全部“読む”、あとで全部“書く”
const widths = items.map(el => el.offsetWidth); // 読みをまとめる
items.forEach((el, i) => {                      // 書きをまとめる
  el.style.width = widths[i] + 10 + 'px';
});

JavaScript のブロッキングと defer / async

ここが「表示が遅い」の最大の原因になりがちなポイントです。HTML パース中に <script>(特に外部ファイル)に出くわすと、標準ではパースを止めてスクリプトを取得・実行します。なぜなら、スクリプトが document.write などで DOM を書き換えるかもしれないからです。結果、<head> に重い JS を素朴に置くと、その間ずっと画面が真っ白になります。

そこで <script> には2つの属性があります。どちらもダウンロードはパースと並行で行い、パースを止めません。違いは実行のタイミングです。

書き方ダウンロード実行のタイミング実行順序向き
<script>(無印)ここで停止して取得取得直後・パースを止めて即実行記述順DOM 操作前提の小さなもの
<script defer>並行で取得HTML パース完了後・DOMContentLoaded の直前記述順を保証DOM に依存する本体スクリプト
<script async>並行で取得取得でき次第すぐ(パースを一時中断)取得順(バラバラ)他に依存しない独立スクリプト
<!-- 標準:ここでパースが止まる。head に置くと表示が遅れる -->
<script src="app.js"></script>

<!-- defer:並行ダウンロード→パース後に“記述順で”実行。多くの場合の正解 -->
<script src="app.js" defer></script>

<!-- async:取れ次第すぐ実行(順番は保証されない)。計測タグなど独立物向け -->
<script src="analytics.js" async></script>
迷ったら defer

アプリ本体の JS は defer が無難です。DOM が出来上がった後に、書いた順番どおりに実行されるため、依存関係が壊れにくい。async は「他のスクリプトにも DOM の完成にも依存しない」もの(アクセス解析やA/Bテストの計測タグなど)に向きます。順番が大事な複数ファイルに async を使うと、実行順が崩れて壊れるのが定番の事故です。

モジュールは標準で defer 相当

<script type="module"> は、書かなくても自動的に defer と同じ挙動になります(パースを止めず、パース後に記述順で実行)。一方で type="module"async を付けると async 挙動に変わります。「module だから安全」と思い込まず、async の有無で順序保証が変わる点に注意してください。JS 全体の基礎は JavaScript も合わせてどうぞ。

表示を速くするコツ

仕組みが分かると、高速化の打ち手は「各工程を、減らす・遅らせる・避ける」に集約されます。

  • CSS は早く小さく:CSS は描画をブロックする。重要な部分だけ先に届け(クリティカル CSS)、残りは後回し。
  • JS は遅らせる:本体は defer、独立物は async<head> に素の <script> を置かない。
  • リフローを避ける:アニメーションは transform/opacity で。レイアウト値の読み書きはまとめる。
  • 画像にサイズを指定width/height(または aspect-ratio)を入れておくと、画像読み込み後の**ガタつき(レイアウトシフト)**を防げる。
  • 配信を速くする:そもそもファイルが速く届けば全工程が前倒しになる。圧縮や CDNHTTP/2・3 が効く。
“なんとなく後回し”は逆効果なことも

async/defer や遅延読み込みは便利ですが、ファーストビューに必要な CSS/JS まで遅らせると、かえって表示が遅く見えます(中身はあるのにスタイルが当たらない一瞬が増える)。「初期表示に要るものは早く、要らないものだけ後回し」の切り分けが肝心です。

まとめ

まとめ

ブラウザは HTML→DOMCSS→CSSOM を作り、合体させたレンダーツリーから レイアウト→ペイント→合成 の順で画面を描きます(クリティカルレンダリングパス)。更新時は、位置・サイズが変われば重いリフロー、見た目だけならリペイントtransform/opacity なら軽い合成のみ<script> は標準でパースを止めるので、本体は defer、独立物は async が基本。「CSS は早く、JS は遅く、リフローは避ける」——この3つを押さえれば、レンダリングの仕組みと高速化の勘所はだいたい掴めます。土台となる HTMLCSS も合わせてどうぞ。

Web/フロントエンド Article

ブラウザのレンダリングの仕組みを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

ブラウザ

比較で見る軸

難易度: intermediate / カテゴリ: Web/フロントエンド / タグ数: 4

導入後に効く点

位置やサイズが変わると レイアウトからやり直す“リフロー”、見た目だけなら“リペイント”。リフローは重いので避け、できれば transform/opacity の合成だけで動かす。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
Web/フロントエンド
タグ数
4

判断チェックリスト

  • 自社の用途が「ブラウザ / レンダリング」に近いか確認する。
  • 強みである「ブラウザは HTML→DOM、CSS→CSSOM を作り、両者を合わせたレンダーツリーから レイアウト→ペイント→合成 の順で画面を描く(クリティカルレンダリングパス)。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

ブラウザレンダリングDOMパフォーマンスブラウザレンダリングDOMパフォーマンス
参考: 公式情報