ページ レイアウトを定義するとき、最初からレンダリングを最適化する必要があります。スタイルとスクリプトはページ レンダリングにおいて非常に重要な役割を果たします。専門家は、パフォーマンスの問題を回避するためのいくつかのコツを知っています。
この記事では、ブラウザーの技術的な詳細については掘り下げず、いくつかの一般原則を説明します。ブラウザエンジンが異なれば動作も異なるため、特定のブラウザの学習がより複雑になります。
ブラウザはどのようにページをレンダリングしますか?
ブラウザがページをレンダリングする一般的なプロセスから始めましょう:
DOM (ドキュメント オブジェクト モデル) は、サーバーから受信した HTML から形成されます。 スタイルはロードされ、解析されて CSSOM (CSS Object Model) を形成します。 DOM と CSSOM に従って、レンダリング ツリーが作成されます。このレンダリング ツリーはレンダリングされたオブジェクトのコレクションです (Webkit ではそれぞれ「レンダラー」と「レンダー オブジェクト」と呼ばれますが、Gecko エンジンでは「フレーム」と呼ばれます)。非表示の要素 (head タグや、display:none 属性を持つ一部の要素など) を除いて、レンダー ツリーは DOM の構造をマップします。レンダリング ツリーでは、各テキスト文字列は独立したレンダラとして扱われます。各レンダー オブジェクトには、計算されたスタイルを持つ対応する DOM オブジェクト (またはテキスト ブロック) が含まれています。言い換えれば、レンダー ツリーは DOM の視覚的表現を記述します。 レンダリング要素ごとに、その座標が計算されます。これを「レイアウト」と呼びます。ブラウザは、一度だけ処理する必要がある「フロー メソッド」を使用してすべての要素をレイアウトします (テーブルは複数回処理する必要があります)。 最後に、ブラウザウィンドウにレイアウトが表示されます。このプロセスを「ペイント」と呼びます。 再描画
位置の変更を必要としないいくつかのスタイル(背景色、境界線の色、可視性など)がページ上で変更された場合、ブラウザは要素に新しいスタイルを再描画するだけです(これは「再描画」または「スタイルの再定義」)。
リフロー
リフロー (または「再レイアウト」) は、ページ上の変更がドキュメント内の要素のコンテンツ、構造、または位置に影響を与えるときに発生します。再配置は通常、次の変更によってトリガーされます:
DOM 操作 (要素の追加、削除、変更、要素の順序の変更など)。 フォーム内のテキストの変更を含むコンテンツの変更。 CSS プロパティを計算または変更します。 スタイルシートを追加または削除します。 「クラス」属性を変更します。 ブラウザウィンドウの操作(サイズ変更、ウィンドウのスクロール)。 疑似クラス (ホバー状態など) をアクティブ化します。 ブラウザはどのようにレンダリングを最適化しますか?
ブラウザは、リフロー プロセスを変更された要素の領域のみに制限するよう最善を尽くします。たとえば、絶対位置または固定位置を持つ要素のサイズを変更すると、それ自体とその子孫にのみ影響しますが、位置が静的である要素に同じことを行うと、その背後にあるすべての要素が再配置されます。
もう 1 つの最適化は、Jjavascript コードの一部を実行するときに、ブラウザーがいくつかの変更をキャッシュし、コードの実行時にこれらの変更を一度に実行することです。たとえば、次のコードは再描画とリフローをトリガーします。
- var $body = $('body');
- $body.css('padding', '1px'); // リフローredraw
- $body.css('color', 'red'); // リフロー
- $body.css('margin', '2px'); // リフロー、再描画
- // 実際にはリフローは 1 つだけです再描画が実行されます。
上で述べたように、要素の属性にアクセスすると、強制的に再配置が行われます。上記のコードに要素の属性を読み取るコード行を追加すると、次の状況が発生します:
- var $body = $('body');
- $body.css('padding', '1px');
- $body.css('padding'); // 要素の属性はここで一度読み取られ、強制的に再配置されます。
- $body.css('color', 'red');
- $body.css('margin', '2px');
上記のコードの結果は、 2 つが再配置されました 回。したがって、パフォーマンスを向上させるには、要素の属性をまとめて読み取るコードを整理する必要があります (詳細な例については、JSBin のコードを参照してください)。
強制再注文 をトリガーする必要がある状況があります。たとえば、同じ属性を要素に 2 回変更し (margin-left など)、最初はアニメーションなしで 100px に設定し、次にアニメーションを通じて値を 50px に変更します。 もちろん、詳細については例を参照してください。
トランジションを含む CSS クラスから始めます:
has-transition 1S Ease-OUT
Transition: Margin-Left 1s Ease-OUT; targetElem = $('#targetElemId');
-
//transition を含むクラスを削除します-
$targetElem.removeClass('has -transition');-
-
//transition を含むクラスがなくなった場合、要素の属性を変更します -
$targetElem.css('margin-left', 100);-
// 次にクラスを追加します戻る遷移を含む
$targetElem.addClass('has-transition');
- //要素の属性を変更する
- $targetElem.css('margin-left', 50);
-
- 上記の実装期待どおりに機能しません。すべての変更はブラウザによってキャッシュされ、上記のコードの最後でのみ実行されます。必要なのは強制的な再配置であり、次の変更を行うことで実現できます:
-
-
- //transition を含むクラスを削除します
- $(this).removeClass('has-transition');
-
- //要素の属性を変更します
- $(this).css('margin-left', 100);
-
- //変更されたクラスまたは属性をすぐに実行できるように、強制的な再配置をトリガーします。
- $(this)[0].offsetHeight; // offsetHeight は単なる例であり、他のプロパティも機能します。
// トランジションを含むクラスを元に追加します
$(this).addClass('has-transition');
- // 要素の属性を変更します
- $(this).css('margin -left', 50);
-
-
これで、このコードは期待どおりに実行されます。 -
- 実際の最適化提案
-
役立つ情報をまとめました。次の点をお勧めします: -
合法的な HTML と CSS を作成し、ファイルエンコーディングを指定することを忘れないでください。スタイルは head タグとスクリプトに記述する必要があります。 tag は body タグの最後をロードする必要があります。 -
CSS セレクターの簡素化と最適化を試みてください (この最適化ポイントは、CSS プリプロセッサを使用するほとんどの開発者によって無視されます)。ネストレベルの数は最小限に抑えてください。 CSS セレクターのパフォーマンス ランキングは次のとおりです (最速から順に): -
ID セレクター: #id-
クラス セレクター: .class-
タグ: div-
隣接する兄弟要素: a + i- 親要素セレクター: ul > ; li
ワイルドカード セレクター: * 擬似クラスと擬似要素: a:hover、ブラウザーはセレクターを右から左に処理することを覚えておく必要があります。そのため、右端の #id と .class のどちらのセレクターが高速になるでしょうか? 。
div * {...} // 悪い
.list li {...} // 悪い
.list-item {...} // 良い
#list .list- item {...} // 良いです
スクリプトでは、DOM 操作をできるだけ減らします。プロパティやオブジェクトを含むすべてのものをキャッシュします (再利用できる場合)。複雑な操作を実行する場合は、「オフライン」要素を操作して (「オフライン」要素とは、DOM オブジェクトから分離され、メモリ内にのみ存在する要素を意味します)、この要素を DOM に挿入するのが最善です。
jQuery を使用する場合は、jQuery セレクターのベスト プラクティスに従ってください
要素のスタイルを変更するには、「class」属性を変更するのが最も効率的な方法の 1 つです。 DOM ツリーの奥深くまで変更を加えるほど、これはより効率的になります (これは、プレゼンテーションをロジックから分離するのにも役立ちます)。
できるだけ、位置が絶対または固定である要素のみをアニメーション化します。
スクロールするときにいくつかの複雑な :hover アニメーションを無効にすることをお勧めします (例: body タグに no-hover クラスを追加する)。このトピックに関する記事があります。
-