フロントエンドの世界に足を踏み入れてしばらく経つと、誰もが一度は「なぜか画面がカクつく」「スクロールが重い」という壁にぶつかる。その時、適当にコードを書き直して祈るような気持ちでデプロイするのは、もう卒業しよう。
今日は、ブラウザという「黒い箱」の中で何が起きているのか、Performanceパネルを使ってその鼓動を聴く方法を伝授する。
—
1. ブラウザの「脳内」で起きていること:レンダリングパイプラインの深淵
ブラウザが画面を描画するまでの道のりは、想像以上に過酷だ。我々が書いたJavaScriptがDOMをいじり、CSSOMが構築され、それらがマージされて「Render Tree」になる。ここまでは序の口だ。
現場で意識すべきは、その後の3つのフェーズだ。
- Recalculate Style(スタイル計算): どのDOMにどのスタイルが適用されるかを計算する。
- Layout / Reflow(レイアウト): 要素のサイズや位置を計算する。これが最も重い。
- Paint(描画): ピクセルを塗りつぶす。
- Composite(合成): 塗り分けられたレイヤーをGPUに送り、最終的な絵として重ね合わせる。
「リフローが発生した」という言葉を耳にしたことがあるだろうか?これはブラウザが「もう一度画面の配置を全部計算し直さなきゃいけない!」とパニックを起こしている状態だ。この処理をMain Threadで何度も繰り返せば、当然ユーザー体験は最悪になる。
2. Performanceパネルでの「解剖」:Main ThreadとFlame Chart
ChromeのDevToolsを開き、Performanceパネルで録画を開始し、対象の操作を行って停止する。そこに表示されるFlame Chartこそが、ブラウザの「心電図」だ。
特に注目すべきは以下の3点だ。
1. Main Threadのタスク: 長い紫色のバー(Recalculate Style)やオレンジ色のバー(Layout)は、君のコードがブラウザに重い負荷をかけている証拠だ。
2. Rendering/Painting/Compositingの比率: 「Paint」が長すぎないか?「Layout」が不要に発生していないか?
3. ロングタスクの特定: 50msを超えるタスクはユーザーに「カクつき」として認識される。ここを削るのがプロの仕事だ。
3. 実践:ブラウザをいじめないコードの書き方
例えば、スクロールするたびにDOMのプロパティを読み取って書き換えるようなコードは、レイアウトの計算を強制的に発生させる(これをレイアウト・スラッシングと呼ぶ)。
以下のコードを見てほしい。悪い例と、それを最適化した例だ。
/
- 【アンチパターン】
- スクロールイベント内で offsetHeight を読み取ると、
- ブラウザは「最新のレイアウトを教えなきゃ!」と強制的にリフローを実行する。
/
const boxes = document.querySelectorAll(‘.box’);
window.addEventListener(‘scroll’, () => {
boxes.forEach(box => {
// 読み取り(Layout発生)
const height = box.offsetHeight;
// 書き込み(Layout発生)
box.style.height = `${height + 1}px`;
});
});
/
- 【ベストプラクティス】
- 読み取りと書き込みを完全に分離し、ブラウザのパイプラインを最適化する。
- FastDOMなどのライブラリが行っている「バッチ処理」の考え方だ。
/
window.addEventListener(‘scroll’, () => {
// 1. まず必要な情報をすべて読み取る(一括で)
const heights = Array.from(boxes).map(box => box.offsetHeight);
// 2. その後、一括で書き込む(ブラウザは最小限のリフローで済む)
requestAnimationFrame(() => {
boxes.forEach((box, i) => {
box.style.height = `${heights[i] + 1}px`;
});
});
});
なぜこれが速いのか?
ブラウザは非常に賢い。一度のタスク内で「読み取り」と「書き込み」が交互に繰り返されると、毎回計算をし直す。しかし、読み取りを先に終え、書き込みを`requestAnimationFrame`(ブラウザの描画タイミングに合わせる仕組み)にまとめれば、ブラウザは「ああ、まとめて処理すればいいんだな」と判断し、効率的に描画を行えるようになる。
4. 最後に:エンジニアとしての矜持
Performanceパネルを見て「どこがボトルネックか」を特定できるようになると、視界が劇的に開ける。「なんとなく重い」という感覚的な悩みから、「ここがLayoutの計算で詰まっているから、CSSのContainプロパティを使ってスコープを限定しよう」という、ロジカルな改善へとシフトできるからだ。
ブラウザの仕組みを知ることは、単なる知識の蓄積ではない。ユーザーの貴重な時間を守るための、我々エンジニアの「誠実さ」の証明なんだ。
次のデプロイの前に、ぜひ一度Flame Chartを眺めてみてほしい。そこには、君の書いたコードがブラウザとどう対話しているか、その物語がすべて記されているはずだ。

コメント