ReflowとRepaintの理解

DOM操作やスタイルの変更を行う際、ブラウザは画面の表示内容を更新するために内部で レンダリングプロセス を実行します。この中で重要な概念が Reflow(リフロー)Repaint(リペイント) です。両者を理解することで、パフォーマンスを意識した効率的なコードを書くことができます。


1. Reflow(リフロー)

  • 定義: DOMやCSSOMに変更が加わり、要素のサイズ・位置・構造が再計算される処理

  • 発生する例:

    • 要素の追加・削除 (appendChild, removeChild)

    • 要素のサイズ変更(width, height, padding, margin など)

    • フォントサイズやウィンドウサイズの変更

    • スクロール発生時のレイアウト再計算

  • コスト: 非常に高い。再計算は変更された要素だけでなく、その子要素・親要素や他の依存関係のあるノードにも影響する。


2. Repaint(リペイント)

  • 定義: レイアウトの位置・サイズは変わらないが、外観(色や背景、ボーダーなど)が変化したために再描画される処理

  • 発生する例:

    • 背景色の変更 (background-color)

    • テキストの色変更 (color)

    • ボーダーの色変更

  • コスト: Reflowに比べれば軽いが、それでも頻発するとパフォーマンスに影響する。


3. ReflowとRepaintの関係

  • Reflowが発生すると必ずRepaintも発生する(レイアウト計算後に描画が必要になるため)。

  • Repaintは単独で発生することもある(色や装飾の変更のみの場合)。


4. パフォーマンス最適化のベストプラクティス

  1. DOM操作をまとめる

    • 繰り返しの操作を避け、まとめて変更する。

    • 例: DocumentFragment を使って複数の要素を一度に追加する。

  2. スタイルの変更をまとめる

    • 複数のスタイル変更を個別に行うと、そのたびにReflow/Repaintが発生する。

    • 解決策: classList.add() でクラスをまとめて変更。

  3. レイアウト情報の読み取りに注意

    • offsetWidth, offsetHeight, getComputedStyle などは強制的に最新のレイアウトを計算させるため、高コスト。

    • 必要最小限に抑える。

  4. アニメーションの最適化

    • レイアウトに影響するプロパティ(top, left, width, height)の変更はReflowを引き起こす。

    • GPUアクセラレーションが効く transformopacity を活用すると、Reflowを避けられRepaintのみで済む。


5. 実例(効率の悪いケースと良いケース)

悪い例(毎回Reflow発生):

javascript
for (let i = 0; i < 1000; i++) { const div = document.createElement("div"); div.textContent = i; document.body.appendChild(div); // 毎回Reflow }

良い例(Reflowをまとめる):

javascript
const fragment = document.createDocumentFragment(); for (let i = 0; i < 1000; i++) { const div = document.createElement("div"); div.textContent = i; fragment.appendChild(div); } document.body.appendChild(fragment); // Reflow 1回で済む

まとめ

  • Reflow: レイアウト再計算(高コスト)

  • Repaint: 見た目の再描画(中コスト)

  • 最適化の鍵: DOM操作やスタイル変更をまとめる、レイアウト情報の読み取りを最小化する、アニメーションにはtransformopacityを活用する。

ChatGPT5 生成日:2025/09/11