明らかに、レイアウト、スタイル、およびスクリプトがレンダリングに直接関係するため、この方向はレイアウト/フロントエンド開発の段階で最適化できます。 これを行うには、適切な専門家が微妙な点を知っている必要があります。
この記事は、ブラウザーの仕組みを正確に伝えることを目的としたものではなく、むしろその一般原則を理解することを目的としていることに注意してください。 さらに、ブラウザエンジンごとに作業のアルゴリズムが大きく異なるため、1つの記事ですべてのニュアンスを網羅することはできません。
ブラウザがWebページを処理するプロセス
開始するには、ドキュメントを表示するときにブラウザのシーケンスを考慮してください。
- DOM(ドキュメントオブジェクトモデル)は、サーバーから受信したHTMLドキュメントから形成されます。
- スタイルが読み込まれて認識され、CSSOM(CSSオブジェクトモデル)が形成されます。
- DOMとCSSOMに基づいて、レンダリングツリーが形成されるか、レンダリングツリーは一連のレンダリングオブジェクトです(Webkitは「レンダラー」または「レンダーオブジェクト」という用語を使用し、Geckoは「フレーム」を使用します)。 レンダーツリーはDOM構造を複製しますが、非
display:none;
要素(たとえば、<head>
、またはスタイルdisplay:none;
要素display:none;
)はここには含まれません。 また、テキストの各行は、レンダリングツリーで個別のレンダラーとして表されます。 各レンダリングオブジェクトには、対応するDOMオブジェクト(またはテキストブロック)、およびこのオブジェクトに対して計算されたスタイルが含まれます。 簡単に言えば、レンダーツリーはDOMの視覚的表現を表します。 - レンダーツリー要素ごとに、ページ上の位置が計算されます-レイアウトが発生します。 ブラウザはフローメソッドを使用します。ほとんどの場合、1つのパスですべての要素を配置できます(パステーブルにはさらに多くの要素が必要です)。
- 最後に、これらすべてがブラウザでレンダリングされます-ペイント。
ページとスクリプトのユーザーインタラクションのプロセスで変更されるため、上記の操作の一部を再実行する必要があります。
塗り直し
ページ上のサイズと位置に影響を与えない要素のスタイルを変更する場合(たとえば、
background-color
、
border-color
、
visibility
)、ブラウザは新しいスタイルを考慮して、それを再びレンダリングします-再描画(または再スタイル)が発生します。
リフロー
変更がドキュメントのコンテンツ、構造、要素の位置に影響する場合、リフロー(または再レイアウト)が発生します。 通常、このような変更の理由は次のとおりです。
- DOMによる操作(要素の追加、削除、変更、再配置);
- コンテンツの変更、含む。 フォームフィールドのテキスト。
- CSSプロパティの計算または変更。
- スタイルシートの追加、削除。
- 属性「
class
」を使用した操作。 - ブラウザウィンドウでの操作-サイズ変更、スクロール。
- 擬似クラスのアクティブ化(
:hover
)。
ブラウザの最適化
ブラウザは、可能な場合、変更された要素内で再ペイントとリフローをローカライズします。 たとえば、絶対位置または固定位置の要素のサイズ変更は、要素自体とその子孫のみに影響し、静的に位置する要素の変更は、それに続くすべての要素のリフローを伴います。
もう1つの機能は、JavaScriptの実行中に、ブラウザーが行った変更をキャッシュし、コードブロックの完了時に1回のパスでそれらを適用することです。 たとえば、このコードの実行中に発生するリフローと再ペイントは1回のみです。
var $body = $('body'); $body.css('padding', '1px'); // reflow, repaint $body.css('color', 'red'); // repaint $body.css('margin', '2px'); // reflow, repaint // 1 reflow repaint
ただし、上で説明したように、要素のプロパティにアクセスすると強制的なリフローが発生します。 つまり、上記のコードブロックで要素プロパティへの呼び出しを追加すると、余分なリフローが発生します。
var $body = $('body'); $body.css('padding', '1px'); $body.css('padding'); // , reflow $body.css('color', 'red'); $body.css('margin', '2px');
その結果、1つではなく2つのリフローが発生します。 したがって、可能であれば、パフォーマンスを最適化するために、要素のプロパティへのアクセスを1か所にグループ化する必要があります( JSBinのより詳細な例を参照 )。
しかし、実際には、強制的なリフローなしではできない状況があります。 タスクがあるとします:最初にアニメーションなしで要素に同じプロパティを適用し(“
margin-left
”を取る)(
100px
設定)、次に
50px
への遷移を通してアニメーション化する必要があり
50px
。 JSBinでこの例をすぐに見ることができますが、ここでも署名します。
最初に、遷移を持つクラスを作成しましょう。
.has-transition { -webkit-transition: margin-left 1s ease-out; -moz-transition: margin-left 1s ease-out; -o-transition: margin-left 1s ease-out; transition: margin-left 1s ease-out; }
次に、次のように計画を実装してみましょう。
var $targetElem = $('#targetElemId'); // , "has-transition" // transition $targetElem.removeClass('has-transition'); // , , transition , $targetElem.css('margin-left', 100); // transition $targetElem.addClass('has-transition'); // $targetElem.css('margin-left', 50);
このソリューションは、期待どおりに機能しません。 変更はキャッシュされ、コードブロックの最後にのみ適用されます。 強制的なリフローは私たちを助けます。その結果、コードは次の形式を取り、タスクを正確に実行します。
// transition $(this).removeClass('has-transition'); // $(this).css('margin-left', 100); // reflow, $(this)[0].offsetHeight; // , // transition $(this).addClass('has-transition'); // $(this).css('margin-left', 50);
最適化のヒント
この記事とクライアント側の最適化の問題に対処するHarbeに関する他の記事に基づいて、効果的なフロントエンドを作成するときに役立つ次のヒントを導き出すことができます。
- 有効なHTMLおよびCSSを記述し、エンコードを示します。 スタイルは
<head>
に、スクリプトは<body>
最後に含めるのが最適です。 - CSSセレクターを簡素化および最適化してみてください(これは多くの場合、プリプロセッサーを使用する開発者によって無視されます)。 ネストが少ないほど良い。 処理効率により、セレクターは次の順序で配置できます(最速から開始)。
- ID:
#id
- クラス:
.class
- タグ:
div
- 近くのセレクター:
a + i
- 子セレクター:
ul > li
- ユニバーサルセレクター:
*
- 属性セレクター:
input[type="text"]
- すべての要素と擬似クラス:
a:hover
ブラウザーはセレクターを右から左に処理するため、最も効果的なもの(識別子とクラス)をキー(右端)セレクターとして使用することをお勧めします。
div * {...} // .list li {...} // .list-item {...} // #list .list-item {...} //
- ID:
- スクリプトでは、DOMでの作業を最小限にします。 すべてをキャッシュする:プロパティ、オブジェクト、再利用する場合。 複雑な操作の場合、「オフライン」要素(つまり、DOM内ではなくメモリ内)を操作してから、DOMに配置するのが妥当です。
- jQueryを使用して要素を選択する場合は、 セレクターのコンパイルのガイドラインに従ってください 。
- 要素のスタイルを変更するには、「
class
」属性のみを変更することをお勧めします。DOMツリー内で可能な限り深く、これは開発とサポート(プレゼンテーションとロジックの分離)の観点からより有能であり、ブラウザーのコストが低くなります。 - 絶対的かつ固定的に配置された要素のみをアニメーション化することが望ましいです。
- スクロール中に複雑なホバーアニメーションを無効にすることができます(たとえば、「
no-hover
」クラスをボディに追加する)。 このトピックに関する記事 。
問題のより詳細な調査については、次の記事を読むことをお勧めします。
すべての読者がこの記事から何か役に立つことを学んだことを願っています。 いずれにせよ-見てくれてありがとう!
UPD:CSSセレクターの処理効率に関する正しいコメントを寄せてくれたSelenIT2とpiumossoに感謝します。