もし速くて軽いアニメーションのライブラリーを探しているなら、Julian Garnierが考案したanime.jsを検討してみてはどうでしょうか。
この記事は、SVG画像を含む動的なDOMアニメーションに関する解説です。記事では、canvas-WebGLやSVGに特化したアニメーションライブラリーに触れるつもりはありません。ただし、WebページのHTML要素(理想的にはSVG画像も)のアニメーションに適していれば、別の機会に紹介するかもしれません。
記事の目的はライブラリーを分析してコードを掘り下げることではありません。主にCSSを使う人が、DOMのアニメーションのためにJavaScriptでなにができるかを追及する、という視点で説明していきます。したがってCSSの開発者にとってなじみやすい構文で、CSSのスタイルやクラスを動的に足し引きするようなDOM操作でアニメーションができる、優れたツールを紹介します。
Web上でのアニメーション
Sarah Drasnerが解説しているとおり、Webアニメーションで考えるべき区別は、ユーザーインターフェース/ユーザーエクスペリエンス(以下UI/UX)のためのアニメーションと、スタンドアロン(単独)のアニメーションです。
動きのある画像を使うと、いかに見る人の理解が進むかを示した研究結果があります。つまり、静止画もしくは連続した静止画を見るよりも、動きのある画像で見たほうが情報をよく理解・吸収できるということです。
UI/UXアニメーションを使う目的は、ユーザーがWebサイト内を移動し、サイトの情報を閲覧し、特定の作業を補助することです。たとえばニュースレターへの登録やショッピングカートへの商品追加がなどです。
一方、スタンドアロンのアニメーションについてはこうです。
補助的に、もしくは単独で、Webページ本文のコンセプトを表現するのに使われる
Sarah Drasner — CSSカンファレンスのスライド
これを具体的にした、Sarahが作ったすばらしいデモがCodePenにあります。
この区別は大切です。ユーザーインターフェイスをアニメーション化するのは、ユーザーがWebサイトの目的に向かう動きを助けるためです。一方、スタンドアロンのアニメーションは、コンセプトを最大限に表現するためなのです。
とはいえ、どちらのアニメーションも訪問者を楽しませるものです。だからこそアニメーションを作るときには、ユーザーを喜ばせるのか、苛立たせたり苦しめるのかを左右する、パフォーマンスとアクセシビリティが重要なのです。
なぜアニメーションにJavaScrioptを使うのか
今日では、CSSの遷移アニメーションでWebページに動きを付けられます。それでも、Webのアニメーションといえば、いまなおJavaScriptが主流です。なぜでしょうか。少なくともCSSだけでアニメーションはできるのに、いったいなぜJavaScriptが必要なのでしょうか。
アニメーションにCSSを使うかJavaScripを使うかを決めるために、Rachel Naborsによる以下の区別を参考にしてください。
- 静的なもの:このタイプのアニメーションは、選択による分岐がなく最初から最後まで実行される。この場合CSSローダーが最適で、この種のアニメーションはCSSのみで作成できる
- ステートフル(状態を保持する)なもの:このタイプのアニメーションのよくある例は、ボタンのクリックで開閉するサイドバーだ。CSSに加えてほんの少しのJavaScriptを使い、アニメーションに関係する要素の状態を保持するCSSクラスを加えたり消したりして作成する
- 動的なもの:このタイプのアニメーションは、ユーザーの選択、DOMイベント、同じページ内のほかの要素のアニメーションの状態などによって異なった動きをする。CSSだけでは作成できないため、JavaScriptが一番良い選択になる
動的なアニメーションの場合以外でも、以下のいずれかの状況ならばJavaScriptを使ったアニメーションが役に立ちます。
- たくさんの要素のアニメーションをつなげたり時間差で実行しなければならないとき。この場合、後に続くアニメーションは前のアニメーションが終わってから動かなければならない。アニメーションの各要素のdelayプロパティを調整すれば、CSSだけでもできる。ただし、たった1つの値でも変更すると以降の要素もすべて調整する必要があり、すぐに管理が難しくなる
- SVG画像をアニメーションにするとき。この場合は、SVG画像のCSSアニメーションは各ブラウザー間で統一的に対応していないことが問題になる
- CSSアニメーションに対応していない古いブラウザーにも対応する必要がある場合、JavaScriptを使った定評ある手法によって、対応範囲の広いアニメーションが作成できる
この話題についてさらに知りたいなら、Greensockアニメーションプラットホームの作者、Jack Doyleが『Myth Busting: CSS Animations vs. JavaScript』に要点を書いています。
将来有望な代替案:Web Animations API
W3Cは、SCC、SVG、JavaScriptのアニメーションを統合し、外部JavaScriptライブラリを必要としない統一の言語仕様の制定に取り組んできました。このAPIはWeb Animations APIとして知られ、これまでCSSに適さなかった動的なアニメーションに最適です。まさにDudley Storeyが書いている『「動き」はどの技術で実装すべきか? Web Animations APIの登場で常識が変わる』が参考になります。
Web Animations APIへの取り組みは着実に進行中で、このAPIをネイティブサポートしていないブラウザーのためにポリフィルも用意されています。
いずれも良いことなので、Web Animations API(WAAPI)を積極的に推奨します。しかし、執筆時点ではブラウザー側の対応は不完全ですし、仕様は将来変わるかもしれません。WAAPIがプロジェクトに最適ではないとすれば、頼れるのはJavaScriptのアニメーションライブラリーになります。
動的なDOMアニメーションのためのアニメーションライブラリー
使えるJavaScriptのアニメーションライブラリーは幅広い選択肢があります。執筆時点では、GSAP(GreenSock Animationプラットホーム)としても知られるGreenSockとVelocity.jsが有名です。
どちらもすばらしく、ユーザーフレンドリーなので、今後、機会があれば触れたいと思いますが、この記事では、大きな人気を獲得しつつある新しいJavaScriptアニメーションライブラリー、anime.jsを取り上げます。
anime.jsの主な機能
「Anime」とは日本語で、手書もしくはコンピューター画像のアニメーションを指す言葉です(日本語で書くと「アニメ」)。
anime.jsの機能については、このように言われています。
柔軟でしかも軽いJavaScriptのアニメーションライブラリー。CSS、個々のTransform、SVG、DOMの属性、JavaScriptのオブジェクトに対応している
anime.jsは以下のブラウザーに対応しています。
- Chrome
- Safari
- Opera
- Firefox
- Internet Explorer 10以降
ほかのアニメーションライブラリーではなく、なぜanimeなのか
答えはanime.jsの作者に答えてもらいましょう。彼はGSAPのようなパワフルなライブラリーがすでにあるなかで、なぜanime.jsを考え出したのかを説明しています。
GSAPはanimeよりももっと多くのことができる。しかしずっと重い。私がこのライブラリーを作った目的は、APIを可能な限りシンプルに保ち、コードを超軽量(最小9KB)に保ったまま、本当に必要な機能(タイミングの調節、イージング、再生のコントロール)に集中することだ
ハッカーニュース(Hacker News)
要するに、HTMLやSVG要素の動的アニメーションに、GSAPやほかの大きなライブラリーが標準搭載するすべての機能を必要としないなら、anime.jsは非常に優れた選択肢なのです。
anime.jsの使い方
以下にanime.jsの基本的な使い方の例を挙げました。ほとんどのアニメーションはデモのために少しゆっくり再生されます。
anime.jsを読み込む方法は、jQueryやほかのなじみのあるJavaScriptライブラリーを読み込む方法と変わりません。
GitHubのプロジェクトページから.zipファイルをダウンロードして解凍し、htmlドキュメントに<script>タグを使ってanime.min.jsを加えてください。
<script src="anime.min.js"></script>
もしくは、npmかbowerも使えます。
npm install animejs
bower install animejs
1つの要素をアニメーション化する:バウンドするボール
animeをセットアップできたら、一番シンプルなアニメーションから始めます。たった1つの要素、上下にバウンドするボールです。
最初のステップは、animeをコールし、アニメーションの詳細データが詰まったオブジェクトを渡します。これが基本的な構文です。
var bouncingBall = anime({
//code here
});
次に上のオブジェクトを、どのようにアニメーションにするのか、どの種類のアニメーションなのか、その時間の長さは、といったことを肉付けします。
var bouncingBall = anime({
targets: '.ball',
translateY: '50vh',
duration: 300,
loop: true,
direction: 'alternate',
easing: 'easeInCubic'
});
targetsプロパティはどの要素をアニメーションにするのかを表します。上の例のようにCSSセレクターを使って指定もできますし、以下に挙げる方法でも可能です。
- DOM要素で指定 — 例:document.querySelector('.ball')
- Nodelistで指定 — 例:document.querySelectorAll('.ball')
- JavaScriptのオブジェクト — 例:{elementName: 'ball'}
- JavaScriptの配列 — 例:['.ball']
もしtargetsプロパティに2つ以上の要素を入れたアニメーションを考えているのなら、以下のように、データ構造に配列を使えば良いのです。
var bouncingBall = anime({
targets: ['.ball', '.kick'],
//rest of the code
});
例の、2つ目のプロパティtranslateYはボール要素を垂直方向に動かします。CSSを使っている人にはおなじみでしょう。Tiffany Brownらは、要素の位置(position)や幅(width)や高さ(height)といったプロパティを変更するのではなく、translateとscaleを使って要素を動かすことを推奨しています。ブラウザーのリフロー(再計算)が回避されることで、アニメーションのパフォーマンスと質が向上するからです。
例の次のプロパティはdurationです。これは、animeにどれだけの時間アニメーションを継続するか指示しています。もし2つ以上の要素のアニメーションを時間をずらして実行するなら、delayプロパティが便利です。
loopプロパティは、animeにアニメーションを何回繰り返すかを指示します。デフォルトの値はfalseで、1回だけアニメーションを実行します。この値をtrueにすればアニメーションを無制限に繰り返し、任意の数をセットすれば正確な実行回数を指定できます。
directionプロパティも、CSSアニメーションと同様にanimeにも用意されており、CSSにあるnormal、reverse、alternateと同じように指定できます。最後の値、alternateは、アニメーションの方向を通常方向と反対方向で切り替えるもので、バウンドするボールにはぴったりです。
最後に、上のコードではアニメーションにeasingプロパティを指定しています。変化の率は一定なのでしょうか。おそらくアニメーションは最初ゆっくり動き出して、速度を上げていくのではないでしょうか。最後には跳ね返るのではないでしょうか。洗練された効果的なアニメーションのために、このeasingの値はまさに重要な要素なのです。
animeで使用できるすべてのイージング機能は、次のシンプルな命令で説明できます。
console.log(anime.easings);
ボールに2つ目のアニメーションを追加する
バウンドするボールが底にぶつかったときに少し潰れるようにしてみましょう。animeではこれを、JavaScriptのオブジェクトの形式で特定のアニメーションパラメーターを加えると実現できます。バウンドするボールの例を使って、望みの効果を表示する方法は以下です。
var bouncingBall = anime({
targets: '.ball',
translateY: '50vh',
duration: 300,
loop: true,
direction: 'alternate',
easing: 'easeInCubic',
//new code
scaleX: {
value: 1.05,
duration: 150,
delay: 268
}
});
上のコードではボールの幅を広げるために新しいプロパティscaleXを加えて、アニメーションのコントロールのための値といっしょに、オブジェクトリテラル形式で値をセットしています。
valueの値は、横軸方向の縮尺を指定して要素の幅を操作します。durationとdelayの値は、それぞれアニメーションの継続時間と、前のアニメーションに対していつあとのアニメーションを開始するかを指定します。
お気に入りのブラウザーの開発ツールでコードを検査すれば、animeがどのように要素をアニメーションにしているかが分かるでしょう。インライン<style>タグを挿入し、CSSのtransformプロパティの値を動的に更新しています。
2つの要素を続けてアニメーションにする:ボールを蹴る
下のサンプルコードは2つの要素、ここでは2つの画像を、続けてアニメーションにする方法の例です。2番目のアニメーションは、最初のアニメーションの完了後に始まります。
var kickBall = anime({
targets: '.kick',
scale: 1.2,
duration: 300,
easing: 'easeInCubic',
complete: function() {
anime({
targets: '.ball',
translateX: '70vw',
scale: 1.5,
easing: 'easeOutBounce',
delay: 150
});
}
});
ボールは、蹴られてからはじめて動き出します。anime.jsではcomplete()メソッドを使ってアニメーションを時間差で実行できます。今回のケースでは、ボールをアニメーションにするためのデータがある2番目のオブジェクトをセットしています。
※Image courtesy of Pixabay.com
もちろんCSSでも、いくつかのキーフレームと格好良いcubic bezierの機能を使えば、短時間でこれに近い静的なアニメーションができます。JavaScriptは一切不要で、ブラウザーネイティブの機能でスムーズなアニメーションが実行できるでしょう。
以下がCSSのみで作ったデモです。
アニメーションの再生・停止・再開
anime.jsではアニメーションをいつ開始・停止・再開するかを.play()、.pause()、.restart()メソッドで操作できます。また.seek()メソッドによって、アニメーションの特定の時点を指定できます。
例として以下に、ボールを蹴るアニメーションを再生ボタンで操作する方法を示します。
//Animating the kick
var kickBall = anime({
targets: '.kick',
scale: 1.2,
duration: 300,
delay: 100,
easing: 'easeInCubic',
autoplay: false
});
//Animating the ball
var movingBall = anime({
targets: '.ball',
translateX: '70vw',
scale: 1.5,
easing: 'easeOutBounce',
delay: kickBall.duration + 100,
autoplay: false
});
/* Playing the animation
when clicking the play button */
btnPlay.addEventListener('click', function(e) {
e.preventDefault();
kickBall.play();
movingBall.play();
});
上のコードについていくつかの注意があります。
- ボタンを使い、蹴る動作とボールの両方のアニメーションを操作するため、2つの別々のオブジェクトを作成した。蹴るアニメーションの中にボールのアニメーションを入れ子にもできるが、経験上ボタンで操作できるのはメインのアニメーションだけだ(この場合は、蹴るアニメーションで、入れ子になるボールのアニメーションは不可)
- ページが読み込まれたときにアニメーションが始まるのを防ぐために、autoplayをfalseにセットする必要がある
- 最後に、望んだとおりに動かすにはkickBallとmovingBallの両オブジェクトの.play()メソッドをコールする
この再生・停止ボタンの動作はCSSのanimation-play-stateプロパティとほんの少しのJavaScriptを使うことでも再現できます。しかし、いったん終了したあとにアニメーションを再開したり、再度正確に同じコースで動かしたくても、CSSではそうはいきません。
anime.jsでインラインSVG属性をアニメーションにする
最後のデモは、インラインSVG画像の属性をアニメーションにする方法です。今回の画像はボールで遊ぶかわいい猫です。
デモではSVG画像を構成するいろいろなパスとシェイプにCSSのクラスを使っているので、コードのなかでターゲットを指定するのは簡単です。
猫の目をアニメーションにする方法は、次のとおりです。
var movingEyes = anime({
targets: ['.inner-left-eye', '.inner-right-eye'],
cy: 400,
duration: 500,
delay: function(el, index) {
var singleDelay = index === 0 ? 300 : index * 500;
return singleDelay;
},
autoplay: false
});
上のコードは、猫の瞳にあたる円形のcy属性の値を変更して、猫の目を下に向けています。
目が順に時間差で動くことに気づいたでしょうか。anime.jsでアニメーションを時間差にする、もう1つのクールな方法を紹介するため、わざと時間差で動かしました。delayプロパティは数値のほか、関数でも良いのです。例のように関数を使うと、アニメーションの開始時間をプログラムで操作できます。関数により、もしアニメーションにする要素が最初のものなら(targets配列の位置0なら)、左目のアニメーションは300ミリ秒の遅れ(delay)になります。そうでなければ、要素は前のアニメーションに対して、配列の要素番号(ここでは1)に500ミリ秒を掛けた時間差(delay)になります。
※SVG graphic adapted from original on Pixabay.com
最後に
記事では、Webにおいてアニメーションがどのように使用されているかの概要から始まり、アニメーションをJavaScriptで作る場合とCSSで作る場合の検討、WebアニメーションAPIの大まかな解説をしてきました。そのあと、アニメーションライブラリーとしてanime.jsを紹介し、特徴のいくつかを見てもらいCodePenの作品に実装しました。
anime.jsは使っていて楽しかったです。よく使用される機能はかなりカバーできており、構文もとても理解しやすく、スムーズで美しいアニメーション効果が作れます。
残念なことですがはじめて使う人には、現時点ではGitHubにあるREADME.mdファイルが唯一の公式ドキュメントだと言わざるを得ません。
とはいえ、GitHubのissuesのセクションは作者Julian Garnierもよく見ているらしく、疑問に対する良い答えが見つかるでしょう。
また、anime.jsをアニメーションのエンジンとして使用したすばらしいデモのコードを深堀りすれば、ライブラリーの使い方をさらに学べます。
- anime.jsのホームページ
- CodePenのデモと例
- Codrops.netのデモ:文字のアニメーション効果の例
- Codrops.netのデモ:背景部分のアニメーション効果の例
- Codrops.netのデモ:洒落たSVG文字のアニメーションの例
- Codrops.netのデモ:マルチレイアウトのスライドショー
- Codrops.netのデモ:SVGによる出現アニメーション
(原文:Animating the DOM with Anime.js)
[翻訳:西尾健史/編集:Livit]