より良いUIのためのWebアニメーション・パフォーマンス
この記事はGoodpatch Advent Calendar 2018 1日目の記事です。
フロントエンド開発をしているとアニメーションを実装する機会が度々あります。たとえば、私が担当しているモチベーションクラウドでは、以下のように円グラフにアニメーションを加えています。
アニメーションを用いる上で意識したいポイントとして「パフォーマンス」があります。アニメーションのパフォーマンスについて、この記事では主に“滑らかさ”を指すことにします。
昨今ではハードウェアの進歩もあり、あまり意識しなくてもアニメーションのパフォーマンスが問題になることは少ないかもしれませんが、少し複雑なアニメーションやアニメーション以外の要因によってアニメーションの品質劣化が起きる場合には多少のテクニックが必要になってきます。
今回はUIにおいてアニメーションのパフォーマンスが重要とされる背景とWebアニメーションにおける実装の基本についてご紹介します。
目次
なぜアニメーションのパフォーマンスが重要なのか
アニメーションを実装する目的は様々ですが、滑らかに動くアニメーションは気持ちが良いものです。世間的には滑らかに動くアニメーションのことを”ヌルヌル感がある”と表現したり、逆に滑らかに動かないアニメーションを”ジャンキー”、”カクつく”、”ちらつく”といった言葉で表現しているようです。
この”ヌルヌル感”についてユーザーインターフェース研究家でもある渡邊恵太さんの著書「融けるデザイン ハード×ソフト×ネット時代の新たな設計論」では以下のように述べられています。
「ヌルヌル動く」という表現は、サクサクより上の評価として使われることが多い。
・・・
この表現はおそらく、動きの連動が高いことが前提のうえで、自分で操作しているのとは若干違う「 すべり」 を感じている様子と筆者は考えている。
つまり、自己帰属感はあるのだけれど、自分が動かす以上に、より素晴らしく補正されたかのように動いてくれる感触表現ではないだろうか。
つまり、滑らかなアニメーション(かつ適切に設計されたアニメーション)はユーザーインターフェースを操作する上で、操作の対象物が身体の延長として感じられるだけでなく、対象物が現実世界と同じ感覚を得られるように”リアル”に動いたり、目的に合わせて修正行動を行うことで、ユーザーとモノの心理的な距離を近づける役割を持っているのではないかと思います。
このように、アニメーションの滑らかさは、ユーザー体験を向上するために重要な役割を果たしています。
アニメーションのパフォーマンスを表す指標
アニメーションのパフォーマンスを表す指標としてfps(Frames Per Second)というものがあります。fpsは動画において1秒間に処理するコマ数のことですが、fpsの数値が高いほど滑らかな動きになります。Webサイトにおいては60fpsが目標値となっており、1秒間に60コマなので1コマあたり16.7ミリ秒で表示する計算になります。
また、Web開発においてはChromeの開発ツールを利用することでfpsの計測を行うことができます。
リアルタイムでfpsを計測する
Chromeを使って閲覧しているWebサイト上で何かしらのアニメーションが行われている場合は[Chrome Dev Tools > Rendering > FPS meter]を使うことでリアルタイムにfpsを計測することができます。下のキャプチャでは”30.5fps”と表示されています。
たとえば、要素数を増やすと動作が重くなり、fpsが”14.8″あたりまで低くなることが分かります。
特定のシーンのfpsを計測する
特定のシーンについて細かく分析したい場合は[Chrome Dev Tools > Performance]で任意のシーンを記録することができます。
Webにおけるアニメーションの実装手段
Web技術を利用したアニメーションはCSSを使う方法とJavaScriptを使う方法があります。
ここでは単純なアニメーションをもとにして、実装内容の比較と特徴についてご紹介します。
CSSによるアニメーション
CSSによるアニメーションではCSS TransitionとCSS Animationがありますが、以下のような特徴を持っています。ここではCSS Animationのコードを例に挙げます。
- 処理が宣言的で比較的簡単に実装できる
- Combosite Threadで実行される → レンダリングコストを抑えやすい
- パターンがある程度決まっている → 単純なアニメーション向き
.box {
/* 省略 */
animation: slide 1s ease infinite alternate;
}
@keyframes slide {
from {
transform: translateX(0);
}
to {
transform: translateX(200px);
}
}
JavaScriptによるアニメーション
JavaScriptによるアニメーションではrequestAnimationFrameがありますが、以下のような特徴を持っています。
- 基本的に処理を自作するかライブラリを使うことになるので実装コストが高い
- Main(UI) Threadで実行される → レンダリングコストが高い
- Canvasの利用や計算処理なども可能 → 複雑なアニメーション向き
const $box = document.querySelector('.box')
const slide = {
current: 0,
direction: 'right',
min: 0,
max: 200
}
const move = () => {
window.requestAnimationFrame(() => {
if (slide.current === slide.min) {
slide.direction = 'right'
} else if (slide.current === slide.max) {
slide.direction = 'left'
}
slide.direction === 'right' ? ++slide.current : --slide.current
$box.style.transform = `translateX(${slide.current}px)`
move()
})
}
move()
他にもWeb Animation APIというJavaScriptでアニメーションを制御するための仕様策定が進んでいます。
- 仕様策定段階なので、ほとんどのブラウザで未対応 → polyfillはある
- CSSライクにJavaScriptによるアニメーションを実装できる
- アニメーションの停止や逆再生などタイムラインを制御できる
const $box = document.querySelector('.box')
$box.animate([
{transform: 'translateX(0px)'},
{transform: 'translateX(200px)'}
], {
duration: 1000,
iterations: Infinity,
direction: 'alternate'
})
レンダリングコストを意識する
アニメーションによって要素が移動するとき、ブラウザは要素を再描画するためにレンダリングの処理を行います。レンダリングのプロセスは以下のようになっています。
引用元:レンダリング パフォーマンス | Web | Google Developers
上記のプロセスの中でLayoutとPaintに影響を与えるCSSプロパティの変更はレンダリングコストが高く、アニメーションの品質劣化に繋がりやすいです。
たとえば、Layoutに影響を与えるCSSプロパティにはdisplay
, width
, height
, left
, top
などがあり、Paintに影響を与えるCSSプロパティにはborder-radius
, background-color
などがあります。
逆にLayoutやPaintに影響を与えないtransformなどはレンダリングコストを抑えることができるため、滑らかなアニメーションを実現しやすいでしょう。
以下は極端なサンプルですが、position
で移動するアニメーションとtransform
で移動するアニメーションの比較です。
▼ position: left
を使ったアニメーション = 2.6fps
実装サンプル
▼ transform: translateX
を使ったアニメーション = 57.0fps
実装サンプル
もし、アニメーションの品質を改善したいときには、レンダリングプロセスを意識して処理の内容を変えてみると良いかもしれません。
また、どのCSSプロパティがどのプロセスに影響を与えるのかをさらに詳しく知りたい方は以下のサイトをご参照ください。
終わりに
今回は、より良いUIを実現するためにアニメーションのパフォーマンスの影響と実装手段について着目してみました。アニメーションを考えることは楽しいものですが、無闇にアニメーションを用いるとユーザーの時間を奪ってしまい、ユーザー体験を損なってしまう可能性があります。
UIにアニメーションを用いる場合はパフォーマンスだけでなく、そのアニメーションを利用することでどのようなメリットがあるのかを考えると良いでしょう。