【実務・中級編】 CSSプロパティのレンダリングコスト分類 – Webブラウザの仕組み実践ガイド

ブラウザの「レンダリング・コスト」を制する:リフロー・リペイントを支配する技術

やあ。現場でコードを書いていると、「なぜか画面がカクつく」「複雑なアニメーションを動かすとCPU使用率が跳ね上がる」という壁にぶつかることはないだろうか。

フロントエンドのパフォーマンスチューニングにおいて、「なんとなくJSを減らす」「なんとなく画像を圧縮する」といった対策はもう卒業しよう。ブラウザが裏側で何をしているのか、その「物理的な制約」を理解すれば、コードの書き方は劇的に変わる。

今日は、レンダリングの心臓部であるReflow(再レイアウト)とRepaint(再描画)、そしてGPUアクセラレーションについて、現場の知見を交えて深掘りしていくぞ。

—

ブラウザが「泣く」瞬間:ReflowとRepaintの正体

ブラウザのレンダリングパイプラインは、大きく分けて以下の5つのステップで動いている。

1. JavaScript(JSでDOMをいじる)
2. Style(CSSを計算する)
3. Layout(Reflow:要素の幾何学的な位置やサイズを計算する)
4. Paint(Repaint:色、影、画像などをピクセルとして塗りつぶす)
5. Composite(ブラウザの層(レイヤー)を重ねて画面を合成する)

ここでの鉄則は、「後ろの工程に行けば行くほどコストが重い」ということだ。

  • Reflow(Layout)を伴う変更: 要素の幅や高さ、フォントサイズなどを変えるとき。ブラウザはページ全体の幾何学を再計算する必要がある。これはブラウザにとって一番の重労働だ。
  • Repaintを伴う変更: 色や背景色、ボーダーの変更。レイアウトには影響しないが、ピクセルを描き直す必要がある。これも地味にコストがかかる。
  • Compositeのみ: `transform` や `opacity`。これらはGPUに処理を丸投げできるため、メインスレッドを止めずに滑らかに動かせる。

—

実践:高コストを避け、GPUを味方につける

フロントエンドエンジニアとして、我々が目指すべきは「Compositeのみ」で完結するアニメーションの構築だ。

以下のコードを見てほしい。左側が「絶対に避けるべきアンチパターン」、右側が「パフォーマンスを意識したモダンな書き方」だ。

/

  • アンチパターン:Layoutを発生させる
  • widthやtop/leftを変えると、毎回ブラウザは再レイアウトを計算し、
  • メインスレッドを占有してしまう。

/
const box = document.querySelector(‘.box’);
box.style.width = ‘200px’; // 毎フレームのリフロー発生源!
box.style.top = ‘100px’; // これもリフローを引き起こす

/

  • 推奨パターン:Compositeのみで完結させる
  • transformとopacityは、ブラウザが別レイヤーで処理するため、
  • メインスレッドへの負荷が極めて低い。

/
const box = document.querySelector(‘.box’);
// 要素の移動には transform: translate を使うのが鉄則
box.style.transform = ‘translate(100px, 100px)’;
// 透明度の変更には opacity を使う
box.style.opacity = ‘0.5’;

—

なぜ「transform」は速いのか?

ここで一つ、君たちに覚えておいてほしいブラウザの裏側の知見がある。
`transform` や `opacity` を使うと、ブラウザはその要素を「独立したレイヤー(Compositing Layer)」として扱うんだ。

例えるなら、巨大なキャンバスに絵を描き直すのではなく、「透明なシートに絵を描いて、それを元の絵の上に重ねる」ようなイメージだ。背景の絵を描き直す必要がないから、GPUの力を使って爆速で合成できる。

ただし、注意点もある。レイヤーを無闇に増やしすぎると、今度はメモリを食いつぶす。 すべての要素を `will-change: transform` でレイヤー化すればいいというわけではない。必要な箇所にだけ、ピンポイントで使うのがプロの仕事だ。

—

今すぐ現場で使える「コスト削減チェックリスト」

明日からの実装で、以下のリストを意識してみてくれ。

  • 幅・高さの変更(width/height)は極力避ける: アニメーションさせるなら `transform: scale()` を使う。
  • 位置の移動は top/left ではなく transform: これだけでカクつきは劇的に減る。
  • DOMの読み書きを交互に行わない: `offsetHeight` などを取得した直後に `style` を変えると、ブラウザは強制的にリフローを実行する(強制同期レイアウトという。これは敵だ)。読み込み(Read)を先に、書き込み(Write)を後にまとめて行うのが鉄則だ。
  • DevToolsを使い倒す: Chrome DevToolsの「Rendering」タブにある「Paint Flashing」をオンにしてごらん。アニメーション中に画面が緑色に光る場所があれば、そこがRepaintされている場所だ。光りすぎている箇所は、最適化のチャンスだぞ。

最後に

ブラウザは優秀だが、魔法使いではない。我々エンジニアが「ブラウザにどう計算させるか」という意識を持つだけで、エンドユーザーが見る画面の滑らかさは段違いになる。

理論を知った上で、現場の泥臭い仕様と戦う。それができるのが、真のフロントエンド・スペシャリストだ。次に画面がカクついた時、ブラウザが裏で泣いていないか、一度想像してみてほしい。

それじゃ、また現場で会おう。健闘を祈る。

コメント

タイトルとURLをコピーしました