17 June, 2017

The pixel pipeline

ブラウザがHTMLをレンダリングする際に何を行っているか

The pixel pipeline


ブラウザがレンダリングをする際に行っていることは、大きく分けると次の5つになる:

pixel-pipeline

  • JavaScript: DOM操作で画面の見た目を変更にかかわるスクリプトの処理。
  • Style: 要素に対してどのCSSルールが適用されているかを計算するプロセス。 .class1.class2のように複数CSSセレクタが該当するものは、CSS適用の優先度から最終的にあてはまるルールを決定する。
  • Layout: 位置, 幅, 高さなど、要素がスクリーンのどのスペースを占めるかを決定するプロセス。Firefoxではreflowと呼ばれる。 width, height, left, top を変更するとLayout処理が発生する。
  • Paint: 描画処理呼び出しリストの作成と要素ピクセルに色で埋める処理(ラスタライズ)を行う。 テキスト、色、画像、ボーダー、影を描画する処理を含む。 color, background-colorborder-radius, border, box-shadowなどを変更するとPaintの処理が発生する。
  • Composite: ブラウザは複数のレイヤ(*1)と呼ばれる単位で描画されている。ページ全体にレイヤが正しい順序で描画を行うプロセス。 transform, opacityの変更はこのプロセスのみを発生させる。

再描画の際に実行されるプロセスが少ないほど高速となるので、アニメーションやスクロールなどの高負荷処理の部分では Compositeのみを発生させるようチューニングするのが望ましい。

Side Navigationでパフォーマンス比較


Side Navigationをアニメーションで表示させてパフォーマンスの違いを確認する

使用するHTML

  <div class="app">
    <div class="side-menu">side-menu</div>
    <div class="header">
      <button class="menu-button">open</button>
    </div>
  </div>

1. leftプロパティでアニメーション

.side-menu {
  left: -102%;
  transition: left 150ms linear;
}

.side-menu--open {
  left: -70%;
  transition: left 150ms linear;
}

2. transformプロパティでアニメーション

will-changeプロパティでレイヤーを生成している。(非対応ブラウザにはtransform: translateZ(0);)

.side-menu {
  transform: translateX(-102%);
  transition: transform 300ms linear;
  will-change: transform;
}

.side-menu--open {
  transform: translateX(-30%);
  transition: transform 300ms linear;
}

比較結果

  1. leftプロパティでアニメーション
    non-optimized

  2. transformプロパティでアニメーション
    optimized

大幅な差は確認できなかったが、transformプロパティでのアニメーションのほうがFPSが安定していることがわかった。 今回は調査しなかったがwill-changeプロパティはGPUメモリにレイヤを格納し続けるのでスマートフォンなどでは電池消費が大きくなるそうで、 アニメーション直前にwill-changeをオンにするのが良い方法らしい。


*1 レイヤー: GPUで処理される領域。GPUへテクスチャとしてアップロードされる。1つのレイヤが大きい場合はより小さいタイルという単位でアップロードされる。

参考

author r-tamura
r-tamura
Web関連多めのソフトウェアエンジニアです。