ノベルティメディア
mediaブラウザレンダリングの仕組みを理解し、Webサイトのパフォーマンス向上を目指す


はじめに
動画クリエーター兼コーダーの川島です。この記事は、Webサイトにおけるレンダリング仕組みの解説を通し、アニメーションなど、Webサイトの動作に伴うカクつきの原因を解消することを目的とした記事です。
普段表立つことのないブラウザの仕組みを理解することで、インタラクティブなWebサイトや、アニメーションを多用することで起こるパフォーマンスの低下を最低限に抑えるためのヒントになればと思います。
パフォーマンスの低下を引き起こしてしまう要因
画面上に表示したWebサイトがアニメーションしているとき、カクカクした動きになってしまうことがあります。この現象の多くは、表示までの処理が重いためにフレームレートが下がってしまっているために起こります。
フレームレートとは
フレームレートとは、Frame Per Second(fps)の略で、「1秒間に何枚の画像を描画できるか」を示す値の単位のことです。ブラウザは最高60fpsまで描画することができるので、1秒間に60回画面が更新されていることになります。つまり、次に表示する画面は常に1/60秒以内に用意されていなければなりません。
例えば、もしこれに1/80秒かかってしまったとしたら、その分1秒間に表示できる画像の数が減ってしまうことになり、結果としてフレームレートは下がって表示されてしまいます。これが「カクカクした動き」の原因です。
ブラウザのフレームレート実数値を最高値で維持し続けさせるために、簡単に言えばWebサイトを表示させるための処理は1/60秒以内に留める必要があります。すなわち、javascriptとレンダリング処理を軽量に行わせ、1/60秒以内に収める必要があるのです。
レンダリングとは
Webサイトは、HTMLやCSSなど様々な言語によって構成されています。しかしこのままでは、これらはただの文字の羅列でしかありません。
レンダリング(演算処理)が行われることにより、プログラミング言語はコンピュータが理解できる形へ変換され、普段目にするWebサイトとして表示されるのです。
ブラウザごとに異なるレンダリングエンジン
ブラウザレンダリングは、レンダリングエンジンとJavaScriptエンジンの2つのソフトウェアによって相互的に行われます。
レンダリングエンジンは「HTMLエンジン」とも呼ばれ、HTMLやCSSなどを画面上で描画する際に動作するソフトウェアです。
JavaScriptエンジンはブラウザでjavascriptを実行するための環境を提供するソフトウェアです。
どちららもブラウザに標準搭載されているものですが、OSやブラウザによって採用されているエンジンが異なります。
ブラウザ(OS) | レンダリングエンジン | JavaScriptエンジン |
---|---|---|
Google Chrome(Windows) | Blink | V8 |
Google Chrome(Windows) | Blink | V8 |
Google Chrome(Android) | Blink | V8 |
Google Chrome(iOS) | Webkit | JavaScriptCore |
Safari(Mac) | Webkit | JavaScriptCore |
Safari(iOS) | Webkit | JavaScriptCore |
Microsoft Edge(Windows) | Blink | V8 |
Firefox(Mac) | Gecko | SpiderMonkey |
Firefox(Windows) | Gecko | SpiderMonkey |
Internet Explorer(Windows) | Trident | Chakra |
例えば、Chromeとsafariで表示が崩れてしまったり差異が生じてしまうのは、レンダリングエンジンが異なるためです。
レンダリングはスレッドという実行単位で行われる
スレッドとは、コードを実行できる機能のことを指します。
これまでにお伝えしたレンダリングの各フェイズは、いくつかのスレッドによって処理されています。
ブラウザレンダリングにおいて、重要なスレッドは以下の2つです。
- Main Thread(メインスレッド)
- Compositor Thread(コンポジタースレッド)
ブラウザレンダリングにおいて、Main ThreadはPaintの一部までの処理やjavascriptの実行など、レンダリング工程において大部分の処理を担っており、これらはCPUによって処理されています。
一方、Compositor Threadは、主にRasterizeとComposite処理を担っており、GPUにより処理されます(事項図1)。
Main Threadへの負荷をなるべく軽減し、Compositor Threadによる処理範囲で変更を行うことは、パフォーマンス向上の観点で非常に重要です。
では具体的に、レンダリング処理の仕組みを見ていきましょう。
レンダリングの仕組み
レンダリングは次の通り、順番に実行されます。
- Download(ダウンロード)
- Parse(パース)
- Scripting(スクリプティング)
- Style(スタイル)
- Layout(レイアウト)
- Paint(ペイント)
- Rasterize(ラスタライズ)
- Composite(コンポジット)

図1:レンダリングの仕組み、担当処理とその流れ
①Download(ダウンロード)
サーバーからデータをダウンロードします。
②Parse(パース)
ブラウザはサーバから受け取ったHTMLとCSSをそのままの形で解釈し表現することはできません。
HTMLはDOM Tree、CSSはCSSOM Treeという、ブラウザ自身が扱うことができる形に変換する作業を行います。この役割を担うのがParseフェイズです。
③Scripting(スクリプティング)
DOMツリーの構築と半ば同時に存在するフェイズです。
基本的には構築されたDOMツリーやCSSOMツリーに対しjavascriptを実行するフェイズですが、DOMツリー構築中であっても、その内容にJavascriptの記述や参照を発見すると、ブラウザはDOMツリーの構築を中断しこのフェイズに移行します。
ちなみに、このようにDOMツリーの構築を中断させてしまうことをParser blockingといい、処理が重くなる原因となります。
④Style(スタイル)
このフェイズでは、前工程で構築されたDOMツリーとCSSOMツリーを結合し、どのスタイルをどの要素に当てるかを計算する処理を行います。
この処理によって結合されたツリーはRender Treeと呼ばれます。Renderツリーは、実際にブラウザ画面で表示されるNodeによって構築されています。
⑤Layout(レイアウト)
先ほど作成されたRenderツリーによってスタイリングされた状態のそれぞれの要素のviewport上での「位置」「大きさ」の計算を行うフェイズです。この工程は、ツリーの上流から下流にかけて再帰的に行われます。
つまり、このフェイズの終了後、アニメーションなどによって親要素のLayoutに関わるプロパティに変更が加わると、その子要素にもこの⑤Layout(レイアウト)以降の処理が再び走ることになってしまい、処理の負荷が上がってしまいます。
⑥Paint(ペイント)
このフェイズでは、これまでの工程で確定された内容をもとに、実際に描画を行います。厳密には、まず要素同士の重なり(z-index)が計算されたあとに行われます。
ここまでの処理を終えると、ようやくMain Threadは解放され、以降の処理はCompositor Threadへ引き渡されます。
⑦Rasterize(ラスタライズ)
そして、実際にピクセルとして描画していきます。この処理フェイズをRasterizeと呼びます。また、モダンブラウザでは、Layer Treeという構造体の生成もRastarizeフェイズで同時に行われます。
Layerツリーを生成する目的は、ある要素に変更があった場合、⑤Layout(レイアウト)フェイズでも解説したように、本来であればそれ以外の要素への影響を考慮し多くの計算を行い直さなければならないところを、要素の情報をレイヤーとして保持しておくことで、その計算処理を最低限に抑え、軽量化させる目的があります。
ちなみに、Layerツリーへの分離は、
- transform
- opacity
- will-change
主に上記のCSSプロパティへの変更を検知し行われます。つまり、アニメーションなどはなるべくLayerツリーへの変更に留める方が、無駄な処理を減らすことができ、軽量化できるわけです。
ただし、一度に保持しておくLayerツリーの数が多くなれば、その分メモリを消費し結果的に処理効率を圧迫してしまう結果を生みます。
特に、will-changeプロパティを持たせると、恒久的に要素をレイヤー化させてしまうので、アニメーションする際のみ付与させるなどの工夫が必要です。
⑧Composite(コンポジット)
ピクセル描画されたLayerツリーを合成し、画面上に表示します。この処理フェイズをCompositeと呼びます。
これで、ブラウザレンダリングの工程はすべて完了となります。
下図は、これまでの工程のタイムラインで示したものです。

図2:ブラウザレンダリングの処理フロー
ブラウザに優しい構築を心がける
フレームレートを維持するために処理を軽くするためには、ブラウザにjsの軽量化と軽負荷なレンダリングを行わせることが重要です。
例えば、要素をアニメーションさせる際、leftプロパティなどを使ってしまうと、レンダリング処理をLayoutフェイズまで再帰させてしまうことになり、Main Threadを圧迫してしまいます。
先述したように、負荷の少ないレンダリングを行わせるためには、処理範囲をCompositor Threadによる処理に留め、プロパティの変更は常にGPUへ任せることです。
自分の記述したjsやアニメーションは、レンダリングフェイズのうちどの段階にアプローチしているのかをしっかりと理解し、ブラウザに優しい構築を心がけましょう。
↓ この記事をご覧の方へおすすめの記事はこちら ↓
おすすめ記事/ PICKUP
記事カテゴリー/ CATEGORY
企業の課題はノベルティひとつで完結
ホームページ制作などのWeb制作をはじめ、
システム開発やマーケティング支援などワンストップで対応
まずはお気軽にお問い合わせください
お電話またはメールでお気軽にお問い合わせください。
各種サービスの資料をご用意しています