この記事では「Anime.jsをプロダクトで使用する4つの理由」と題して、Anime.jsを実際にプロダクトで使用した中で見えてきたポイントについて、以下の順番でまとめたいきたいと思います。
- 軽量で扱いやすい(実装したいアニメーションがシンプルなものだったため)
- 公式ドキュメントが読みやすい
- チームでの開発/運用がしやすい
- 変更が容易(突発的な仕様変更にも耐えうる)
一つずつ、詳細に見ていきます。
理由1: 軽量で扱いやすい
Anime.jsはシンプルながらもパワフルな、JavaScriptアニメーションライブラリです。
GitHubスター数は39,900(2021年7月現在)と人気で、また、その機能の豊富さ・手軽かさから、はてなブログでも一時期話題となりました。
はてブスター数は996(2021年7月現在)
そしてminifyがかかったビルドファイルが総容量は17.3kbと、非常に軽量です。
またその軽量さとは裏腹に、CSSプロパティ、SVG、DOM操作といった多彩なアニメーションが可能です。
Anime.js (/ˈæn.ə.meɪ/) is a lightweight JavaScript animation library with a simple, yet powerful API.
It works with CSS properties, SVG, DOM attributes and JavaScript Objects.
理由2: 公式ドキュメントが読みやすい
個人的な推しポイントとしては、ドキュメントの読みやすさです。
ライブラリの使用方法が直感的にわかる、非常に読みやすいドキュメントとなっています。
↓公式Documentの一部を画面キャプチャしたもの。画面右側にはコードの記述例が書かれており、その動きを画面左側で実際に確認することができる(マウスオーバーすることでアニメーションが動作する)。
軽量であるだけでなく、ドキュメントも読みやすく、非常に使いやすそうな点が導入の要因となりました。
(実際にプロジェクトで使用してみて、混乱するようなことはとても少なかったように感じます。)
理由3: チームでの開発/運用がしやすい
アニメーションライブラリの選定にあたっては、パフォーマンスを重要視した上で、それと同じくらいに、今後もチームで継続的に使用していけそうかという観点を意識していました。
# 意識した優先順位
パフォーマンス(速さ、軽さ) == コードの可読性、メンテナンス性(チーム開発に適しているか) <<< 機能の豊富さ
この点に関して、Anime.jsは比較的コードの可読性・メンテナンス性が高いと言えます。
それは一つ一つのアニメーションをJavaScriptのオブジェクトとして管理することができるためです。
アニメーションをオブジェクトとして管理する
ここでは例として、Anime.jsを使用した簡単なアニメーションの実装を見てみましょう。
// 下記のようにアニメーションを定義します。
const nankaUgoki = {
targets: "#nanka", // DOMを指定. 配列で複数指定することも可能.
easing: "linear", // easingの設定値は他にも多数あり
duration: 1000, // 動作にかかる時間を設定
translateX: 250, // 加えたいアニメーションを記述. 基本はCSSプロパティを設定する.
rotate: 2, // アニメーションは複数指定可能
begin: function () {
// アニメーション開始時に実行される処理を記述する
},
complete: function () {
アニメーション完了時に実行される処理を記述する
},
// その他にも多数のプロパティを設定できます。
}
// 実行には anime()メソッドを使用します。
anime(nankaUgoki) // 指定したDOMが動く
上記のように、個々の動作をオブジェクト単位で管理することで、コードのメンテナンスが快適になりました。
このようなわかりやすいインターフェースは、初めてコードを見た人にとっても、理解し易いものかと思われます。
また、動作とターゲットを一つのオブジェクトでまとめて管理できるのも面白いポイントであり、コードを通して実際の動作をイメージすることが容易なのも嬉しい点です。
これらの点がチームでの開発・メンテナンスを容易にしてくれると感じました。
理由4: 変更が容易
Anime.jsには、複数のアニメーションを同期的に連結する Timelines
という機能があります。これを使用することで、個々のアニメーションの実行順序を制御することができます。
Timelines let you synchronise multiple animations together.
実行の順序を制御するだけの機能ではありますが、これが可能であることにより、複雑なアニメーションを、小さなアニメーションの集合体として分割することができます。
アニメーションを連結する
以下の例では、「小さなアニメーション」を連結して、「連続した複雑なアニメーション」を実装しています。
// timelineを初期化する
const renzokuShitaUgoki = Anime.timeline({
easing: "linear", // 初期値を設定可能
duration: "1000", // addした個々の動きは初期値を継承する
});
// 小さな動きを作っておく
const tiisanaUgoki01 = {
targets: '#nanka',
duration: 2000, // 初期値が上書かれる
translateX: 250,
}
const tiisanaUgoki02 = {
targets: '#nanka',
duration: 500,
translateY: 100,
}
// timelineに `add` メソッドを使って動きを追加する. 追加した順番にアニメーションが行われる.
renzokuShitaUgoki.add(tiisanaUgoki01).add(tiisanaUgoki02);
// この場合は、2000msかけてX方向に250px移動した後、500msかけてY方向に100px移動する。
大きなアニメーションをイチから作り上げるのではなく、小さなアニメーションを組み合わせて一つの大きなアニメーションを組み上げるイメージです。
一つ一つの動作がオブジェクト化されているため、部分的に動作を追加したり、また調整したりといったことが行いやすいため、とても開発者フレンドリーな機能だと言えます。
実装途中に仕様変更が発生しても、該当箇所に対応するオブジェクトを調整することで、柔軟な対応を行うことが可能です。
詰まったところ
開発中に何点か詰まったところがあったため残しておきます。
動きが複雑になってくると実装が難しい
例えば、translateX: ["0", "100%"]
のように開始位置と終了位置を定義することはできても、translateX: ["0", "40%", "100%"]
のように中間点を追加することができません。
// OK!
anime({
targets: '#nanka',
translateX: ["0", "100%"], // 開始位置と終了位置を設定可能
})
// NG!!
anime({
targets: '#nanka',
translateX: ["0", "40%", "100%"], // しかし中間点を追加することはできない
})
このように細かく動きを調整する場合は、工夫が必要となってきます(例えば["0", "40%"]のオブジェクトと["40%", "100%"]のオブジェクトの二つに分割して連続で動作させるなど)。
CSSのdisplayプロパティの操作ができない
anime({ display: 'none' })
という制御が効きません。
そのため、とあるタイミングでDOMを表示/非表示した...というときには、begin
や complete
といったプロパティを使用したり、あるいは opacity
を使用するといった代替表現をする必要があります。
// NG!
anime({
targets: '#nanka',
duration: 300,
display: 'none', // 300ms後にふわっと要素を消したい => NG!
})
// OK!!
anime({
targets: '#nanka',
duration: 300,
opacity: 0, // 300ms後に要素を透明にし、
complete: function () {
// 完了後に直接DOMを消す
document.querySelector('#nanka').style.display = 'none';
}
})
おわりに
本記事では「Anime.jsをプロジェクトで使用する4つの理由」として、Anime.jsをプロダクトの中で使用した際によかったと感じた点について記しました。
ライブラリを選定する際には、他のCanvasライブラリやAdobe Animateなど多様なものを比較しましたが、今回はAnime.jsがうまくはまりました。
必ずしも万能なライブラリとは言い切れませんが、使い所にマッチすれば、非常に強い力を発揮するでしょう。