🗂
パフォーマンス低下の原因はこれ!?リフローの原因とその対策方法
はじめに
cssアニメーションを実装していたところ、一部のHTML要素が見えなくなってしまいました。
開発者ツールを開いたところ要素が表示されたので、調べたところリフローが影響していそうでしたので調べてみました。
上記の原因
CSSやJavaScriptでスタイルや位置を動的に変更した場合に、ブラウザが要素のレイアウトやスタイルのリフローを正しく行えずに要素が見えなくなったりパフォーマンスが低下することがあるようです。
「はじめに」で記述したケースは開発者ツールを開くことで、ブラウザが強制的にリフロー、レイアウトを再計算して要素が表示されたようでした。
リフローが起きているかどうか確認方法
Chrome Developer ToolsのPerformanceタブを使用
アニメーションを入れている場合はリフローが基本的に起きていると思いますが、下記のように確認できます。
- Chromeのデベロッパーツールを開く
- Performance タブを選択
- 「Record」ボタンを押して、ページの操作を記録
4. Recordボタン押下後にリロードや疑わしいページの操作(クリックなど)を行います - 記録を停止して結果を確認
- 「Layout」の確認
6. 記録データ内に「Layout」という項目が表示されるのですが、これがリフローの発生を表します - 「Layout」の頻度や発生箇所を確認して、リフローの原因を特定
リフローが発生する主な原因
- DOMの変更
- 新しい要素を追加・削除したり、既存の要素を移動した場合
const element = document.createElement('div');
document.body.appendChild(element);
- CSSの変更
- 要素のスタイル(例: width、height、margin など)を変更した場合
element.style.width = '10px';
-
ウィンドウのリサイズ
- ビューポートのサイズが変わると、レイアウト全体を再計算します。(今回のパターン 開発者ツールを開くとブラウザウィンドウのリサイズなどにより要素のレイアウトが再計算されたことが考えられます)
-
フォントの変更
- フォントサイズやフォント自体を変更すると、テキストのサイズが変化し、リフローが発生します。
-
JavaScriptによる操作
- element.offsetHeightのようなプロパティにアクセスすることで、ブラウザがレイアウトを再計算します。(Forced Reflow)
リフローによるパフォーマンス低下への対策
リフローの回数を減らす
下記のような方法でできるだけリフローを減らします。
- スタイル変更を一括変更
- 一括変更することでリフローの実施を1回に納める。
- クラス付与することで一括してスタイル適用する。
element.style.width = '10px';
element.style.height = '10px';
element.classList.add('new-class');
- DOMの更新を一度にまとめる
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10000; i++) {
const div = document.createElement('div');
fragment.appendChild(div);
}
document.body.appendChild(fragment);
- requestAnimationFrameを利用してリフロー後のレンダリングを制御/最適化
requestAnimationFrame(() => {
el.style.transform = 'translateY(0)';
});
-
アニメーションをGPUで処理
- transformやopacityの変更のみを行うことで、GPUアクセラレーションを活用
-
will-changeを使用する(最終手段)
will-changeは将来プロパティが変更することを予告して、最適化することができます。
使いすぎると逆にパフォーマンス低下する場合もあり、最終手段となります。
参考
Discussion