クイックリファレンス

Layout Thrashing(強制同期レイアウト/Forced Reflow)チートシート

Layout Thrashing と Forced Reflow の総合リファレンス:DOM 要素プロパティ、マウスイベント、window メソッド、および描画パフォーマンスを低下させる jQuery 操作一覧。

· 公開日

Layout Thrashing(強制同期レイアウト/Forced Reflow)とは、JavaScript が DOM への書き込みとレイアウト属性の読み取りを交互に繰り返すことで、ブラウザに同期的なレイアウト再計算を強制してしまう現象です。

レイアウト無効化(Layout Invalidation)のトリガー

先行する DOM 変更によってレイアウトが無効化されている状態で以下のプロパティ・メソッドを参照すると、ジオメトリの同期再計算が強制されます。

要素(Element)のプロパティ&メソッド

ボックスのジオメトリ・寸法

  • clientHeight, clientWidth
  • clientLeft, clientTop
  • offsetHeight, offsetWidth
  • offsetLeft, offsetTop
  • offsetParent
  • scrollHeight, scrollWidth
  • scrollLeft, scrollTop

バウンディングボックスの取得

  • getBoundingClientRect()
  • getClientRects()

スクロール操作

  • scrollIntoView()
  • scrollIntoViewIfNeeded()
  • scrollByLines()
  • scrollByPages()

テキスト・フォーカス

  • innerText
  • outerText
  • focus() (フォーカスリングおよびスクロール位置調整を強制)

マウスイベントプロパティ

MouseEvent インスタンスの特定座標を参照すると、一部ブラウザエンジンでレイアウト計算が発生します:

  • layerX, layerY
  • offsetX, offsetY

Window メソッド&プロパティ

  • window.getComputedStyle() (width、height、margin、transform などレイアウト依存の値を取得する場合)
  • window.scrollBy()
  • window.scrollTo()
  • window.scrollX, window.scrollY

Frame・Document・Image

  • レイアウト確定前に画像の width や height を参照する操作
  • document.body.scrollHeight へのアクセス

jQuery 操作

jQuery の多くのヘルパーメソッドは内部で算出済みレイアウト値を読み取ります:

// リフロー(Reflow)を発生させる呼び出し
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width');  // レイアウト依存のスタイル計算すべて
$(elem).text();

// 幾何学的な可視性を検査する擬似セレクタ
$(':hidden');
$(':visible');
$(':contains');

Layout Thrashing を防ぐベストプラクティス

1. 読み取りと書き込みをバッチ処理する

必ずすべての DOM 計測を先に済ませ、その後まとめて DOM 更新を行います。

// NG: 読み取りと書き込みが交互になり毎回強制レイアウトが発生
elements.forEach((el) => {
  const width = el.clientWidth; // 読み取り(レイアウト強制)
  el.style.width = width * 2 + 'px'; // 書き込み(レイアウト無効化)
});

// OK: 読み取りをまとめてから、書き込みをまとめる
const widths = elements.map((el) => el.clientWidth); // 一括読み取り
elements.forEach((el, index) => {
  el.style.width = widths[index] * 2 + 'px'; // 一括書き込み
});

2. requestAnimationFrame を活用する

スタイル変更を次のアニメーションフレームにスケジュールし、ブラウザの描画サイクルを最適化させます:

const height = element.clientHeight; // 現在のフェーズで読み取り

window.requestAnimationFrame(() => {
  element.style.height = height + 50 + 'px'; // 次のフレームで書き込み
});

3. CSS Transform と Opacity を使う

アニメーションにはレイアウト系プロパティ(top、left、width、height)ではなくコンポジタ処理可能な CSS プロパティ(transform、opacity)を使いましょう。


参考リンク

関連テーマ