おそらく多くの方がsteps()をCSSアニメーションで使うのに苦労なさっていることでしょう。筆者も最初は何のためにどうやって使うのかわからず検索してみたところ、2つの例を発見しました。Lea VerouによるタイピングデモとSiumaiのアニメーションスプライトシートです。
この2つの例はこの微妙なタイミング関数の使い方を覚えるのに大変役立ってくれました。あまりにも要点を突きすぎていて、この例以外の場面でどうやってsteps()を使うんだろうと悩んでしまうほどでした。
こうして、steps()の使い方がわかった筆者は同じようにこのつかみどころのない難敵に苦戦している皆さんのためにいくつかのアニメーションデモを作ってみました。
Stepsの概要
steps()はある状態からほかの状態への移行ではなく、アニメーションやトランジションをいくつかのセグメントに分割する際に使用するタイミング関数です。steps()には2つのパラメーターがあります。1つ目はアニメーションのステップの正数を指定します。
steps(<number_of_steps>, <direction>)
2つ目のパラメーターは@keyframesで動作が実行されるタイミングを指定します。この値はオプションで、何も指定しなければ規定値は「end」です。「start」の方向は左連続関数を表し、アニメーションの最初のステップは開始とともに完了します。最初のステップの一番最後まで飛ばし、このステップが終了するまでその位置にとどまり続けることもできます。「end」の方向は右連続関数を表し最初のステップが終了するまでの間動作を停止します。どちらのオプションも基本的に要素を反対側から動かして同じアニメーションの中で様々なポジションを作り出します。
図にするとこうです。
Fill ModeとIteration Countの影響力
説明を始める前に、まずは「forwards」や「infinite」の使い方のようなfill modeやiteration countがsteps()にどのような影響を及ぼすのか知っておくことが重要です。2つの車が同じアニメーションのデュレーションの同じsteps()の値にあるとします。1台はずっと動き続けるよう設定し、もう1台にはアニメーション終了時の設定を適用した場合、たとえ同じy軸上の点からスタートしたとしても2台の終点は全く異なります。
「forwards」を使うとアニメーションの要素がアニメーションの最後の@keyframesのスタイルを延長してそのデュレーション以降も同じ状態のまま再生できます。これをsteps()と組み合わせることにより、アニメーションの最初の動きのない状態が「end」を使った時のようにステップの合計に加算されていないように見えるわけです。見方によっては、steps()を宣言する前から車が追加のステップを取っているようにも見えます。
ちょっと混乱してきたかもしれないので、デモで説明します。覚えていただきたいのはこうした設定をすることでアニメーションの方向性やステップ数にどんな影響があるかということです。
1 .contain-car {
2 animation: drive 4s steps(4, end) infinite;
3 }
4
5 .contain-car-2 {
6 animation: drive 4s steps(4, end) forwards;
7 }
さて、ここからはさらにコードを見て使い方を理解していきます。
Stepsのデモ
こちらで、以下のようなデモを見ることができます。
・シンプルな時計のCSSアニメーション
・燃費のいい車のCSSアニメーション
・動くクマの足跡
・「進行中」の円のCSSアニメーション
時計のCSSアニメーション
時計はsteps()を解説するのに最適な題材です。時計の針を動かさなくてはいけませんが、その動きはスムーズではなく、かつ継続しなくてはいけません。steps()を使うことで本物の時計の針のような動きが再現できます。
steps()を扱うにはちょっとばかり数学の知識が必要ですが、そんなに難しくはありません。秒針を60ステップで360度回転させ、60秒でアニメーションを完了させます。
1 .second {
2 animation: tick-tock 60s steps(60, end) infinite;
3 }
4
5 @keyframes tick-tock {
6 to {
7 transform: rotate(360deg);
8 }
9 }
時計のアニメーションの宣言は1秒あたり1ステップに分割されます。
分針を動かすには、同じ@keyframesを違うタイミングで割り当てます。60×60でアニメーションの長さが導き出せます。針は60秒に1回動き、60回で360度回転します。
1 .minute {
2 animation: tick-tock 3600s steps(60, end) infinite;
3 }
これで完成です!
注意:この時計はあくまでもCSS時計ですので、実用性はありません。
車のCSSアニメーション
車のアニメーションでは、steps()の中で「end」を使った場合と「start」を使った場合とではどのような違いが出てくるかを見ていきます。「start」を使うと車はすぐに動き始め、そのステップが完了するまでずっとそのまま動き続けます。「start」の車の方が「end」の方に比べてずいぶん右にある感じがしますが、「end」の方にanimation-delayを指定すれば2台が同じy軸上の点からスタートしたように見えます。
「end」は基本的にアニメーションが動き出す前にそのステップの指定した時間を完了します。1台目の車が動き出す前に、2番目のステップに入っているため、車が同時に動くことはなくなります。デモ中の白い線はアニメーションの始点と終点を表しています。
1 .contain-car {
2 animation: drive 4s steps(4, end) infinite;
3 }
4
5 .contain-car-2 {
6 animation: drive 4s steps(4, start) infinite;
7 }
8
9 @keyframes drive {
10 to {
11 transform: translateX(640px);
12 }
13 }
クマの足跡のCSSアニメーション
steps()の理解には、文字通りの「(歩行の)ステップ」を作ってみるのも効果的です。この例ではクマの足跡を使います。このデモでは、6つのクマの足跡の画像を使用しています。この画像には<div>が使われていますが、step()によって<div>を動かし、実際に足跡が付いていく様子を再現します。
steps()を使わずに<div>を動かすと足跡がスムーズに流れるような動きになってしまいますが、この場合はそれではいけません。それぞれの足跡がはっきりと1回1回現れるようにしたいのです。
前述の通り、足跡は全部で6つです。<div>を画像全体(675px)で動くようにして足跡全体が一度で現れるようにします。
1 .cover {
2 animation: walk 7s steps(7, end) infinite;
3 }
4
5 @keyframes walk {
6 to {
7 transform: translateX(675px);
8 }
9 }
<div>は7秒で7ステップかけて675pxの画像を右方向へと渡り切ります。つまりはそれぞれのステップの長さが96pxになります。「end」により最初の1秒間のステップが完了するまですべての足跡が最初の状態をキープします。
「進行中」の円のCSSアニメーション
このデモでは「start」をアニメーションの透明度を変えるのに使います。アニメーションの透明度を変えるのにsteps()を使うと、はっきりと段階的に透明度が変わっていきます。「start」を使うことでたとえ最初の透明度が「0」であってもすぐに色が見えるようにできます。この例で「end」を使うと透明な円から始まります。
透明度は5秒間で5ステップかけて変化します。つまり、1ステップの長さは1秒です。
1 .circle {
2 animation: fill 5s steps(5, start) forwards;
3 }
4
5 @keyframes fill {
6 to {
7 opacity: 1;
8 }
9 }
パーセンテージもsteps()によって変わります。
1 .percentage {
2 animation: load 4s steps(4, end) forwards;
3 }
4
5 @keyframes load {
6 to {
7 transform: translateY(-380px);
8 }
9 }
同じ<div>上にあるパーセンテージは380pxを上に移動します。「20%」は最初から円上にあるので、4ステップかけて<div>を40%、60%、80%、100%にしていきます。
また、「forwards」を使うと前のデモで「infinite」を使った時とは違った影響がステップ数に出てきます。「infinite」に変えてしまうと「100%」は現れなくなってしまいます。「forwards」が宣言したsteps()以外のステップに進むよう命令してしまうからです。
Stepsはコツをつかめばとても便利
steps()は理解するのが難しいですが、いったんコツをつかんでしまえばとても便利なタイミング関数です。このCSS関数を使えばアニメーションの動きをはっきり段階的にしたり、滑らかな動きを手早く作ることができます。
皆さんが苦労なくsteps()を使えるようになるためにこのデモが役立てば幸いです。皆さん、steps()をエンジョイしてくださいね!