KDE BLOG

Webデザインやコーディングについて書いています

CSS3 animationのまとめ(基本編)

前回のtransitionに続き、animationについてもまとめておきます。
transitionよりも長くなりそうなので基本編と発展編に分けたいと思います。
まずは基本編から。

<目次>

animationのできること

transitionは変更前と変更後の2点を結ぶ機能なのに対して、animationではキーフレームでアニメーションを定義できることから、transitionよりも複雑な動きを作成することができます。
例えばページ読み込み時に表示されるローディングgifの代わりにcss animationを使ってリッチな表現が可能です。(参考:待ち時間をもっと楽しく!コピペできるCSSローディングアニメーション38個まとめ

animationをサポートするブラウザも増えてきた上(というよりは古いブラウザへの対応が減ってきた)、基本的にJavaScriptでのDOMアニメーションよりもパフォーマンスが優れているため、現在はJavaScriptではアニメーション開始のきっかけ(イベント)を作り、アニメーション自体はcss transitionやanimationで表現する、というのが主流になってきています。

対応ブラウザ

IEはtransitionと同じく10以上から対応で、基本的に現在のモダンブラウザであれば利用できます。
androidは4.4までベンダープレフィックスが必要なので、現在はまだ-webkit-をつけた方が無難です。
詳しくはCan I useをご確認ください。

各プロパティの概要・構文

animation-name

利用する@keyframesの名前を指定します。
つまりどの動きのアニメーションを利用するかの指定です。

selector1 {
  animation-name: none; /* 初期値。アニメーションさせない意味。 */
}
selector2 {
  animation-name: anim[, <name>[,...]]; /* 複数指定の場合はカンマで区切る */
}

animation-duration

1回のアニメーションが完了するまでの時間。 単位はs(秒)もしくはms(ミリ秒)。

selector1 {
  animation-duration: 0s; /* 初期値。実質、遅延をさせない意味。 */
}
selector2 {
  animation-duration: .3s(300ms)[, <time>[,...]]; /* 複数指定の場合はカンマで区切る */
}

animation-timing-function

3次ベジェ曲線を指定します(基本的にはイージングと考えてOK)。 プロパティ値はtransition-timing-funtionと同じです。

selector1 {
  animation-timing-function: ease; /* 初期値 */
}

selector2 {
  animation-timing-function: ease, linear[, <function-name>[,...]]; /* 複数指定の場合はカンマで区切る。*/
}

上記の指定では、1回のアニメーション全体のベジェ曲線を指定していますが、@keyframes内でキーフレーム間ごとに再定義が可能です。

▼デモ

codepen.io

基本は右に行って帰ってくるアニメーションです。

demo1では@keyframes内ではイージングを指定していません。
animation-name定義時にanimation-timing-function:linear;を指定しているので全体を通して等速で移動します。

demo2ではdemo1をベースに、@keyframes内でanimation-timing-function:steps(4, start)animation-timing-function:steps(8, start)を設定しています。
デモの通り、行きと帰りのアニメーションで異なったステップ数になったのを確認できます。

demo3ではdemo2をベースに、animation-name定義時にanimation-timing-function:ease-in;を指定しています。 最初、私はこのease-inが効いてステップのアニメ含めて全体がease-inのイージングがかかると思っていたのですが、結果は違いました。demo2と全く同じ動きになります。
つまり、@keyframes内でイージングを指定するとそのキーフレーム間はそのイージングが適用されます。全体のイージングは無視されます。 そもそも冒頭で再定義と言っているので当たり前といえば当たり前なのですが…。

demo4ではdemo3をベースに、行きの時だけ@keyframes内でイージングを指定します。
その場合は、行きはそのイージングが適用され、帰りは全体にかけたイージング(ease-in)が適用されます。

animation-delay

アニメーションを開始するまでの遅延時間。 単位はs(秒)もしくはms(ミリ秒)。

selector1 {
  animation-delay: 0s; /* 初期値。実質、遅延をさせない意味。 */
}
selector2 {
  animation-delay: .3s(300ms); /* 0.3秒遅延させる */
}

selector3 {
  animation-delay: .3s(300ms)[, <time>[,...]]; /* 複数指定の場合はカンマで区切る */
}

transition-delayと同じく使い方次第で強力な効果を発揮します。
詳しくは発展編で紹介します。

animation-iteration-count

アニメーションを何回実行するかの指定。

selector1 {
  animation-iteration-count: 1; /* 初期値。1回だけ実行される。 */
}
selector2 {
  animation-iteration-count: infinite; /* 無限 */
}

selector3 {
  animation-iteration-count: 1[,<number>[,...]]; /* 複数指定の場合はカンマで区切る */
}

▼デモ
codepen.io

基本的にはinfiniteか整数を設定するのですが、小数の指定も可能です。
小数の場合はアニメーションの途中で終了します。たとえば0.6だと全体の60%の位置で終了します。
負の値の場合は0とみなされアニメーションしません。

animation-direction

アニメーションのサイクルごとに実行方向を指定。

selector1 {
  animation-direction: normal; /* 初期値。順方向のアニメーションのみ実行 */
}
selector2 {
  animation-direction: reverse; /* 毎回逆方向のアニメーションのみ実行。(イージングも逆になる) */
}
selector3 {
  animation-direction: alternate; /* 順方向 → 逆方向を繰り返す。(逆方向時はイージングも逆になる) */
}
selector4 {
  animation-direction: alternate-reverse; /* 逆方向 → 順方向を繰り返す。(逆方向時はイージングも逆になる) */
}

selector5 {
  animation-direction: normal[,<direction>[,...]]; /* 複数指定の場合はカンマで区切る */
}

これは言葉では伝わりにくいのでデモをご覧ください。

codepen.io

基本は右に500px動いたあと、左に250px動くというアニメーションです。イージングはease-in(最初ゆっくり)を指定しています。

demo1は初期値のnormalを指定しているので、@keyframesで指定した通りの動きになります。

demo2はreverseを指定しています。毎回、逆方向(@keyframesの100%→0%)の動きになります。
またイージングも逆になります。今回はease-inを指定していたので、逆のease-out(最後ゆっくり)の動きになります。

demo3はalternateを指定しています。初回normalの動き → 次回reverseを繰り返します。

demo4はalternate-reverseを指定しています。初回reverse → 次回normalを繰り返します。

animation-fill-mode

アニメーションの開始前や終了後に、@keyframesで指定したスタイルを適用するか指定。

selector1 {
  animation-fill-mode: none; /* 初期値。アニメーション開始前/終了後に@keyframesのスタイルを適用しない */
}
selector2 {
  animation-fill-mode: forwards; /* アニメーション終了後、@keyframesのスタイルを適用*/
}
selector3 {
  animation-fill-mode: backwards; /* アニメーション開始前、@keyframesのスタイルを適用 */
}
selector4 {
  animation-fill-mode: both; /* forwardsとbackwordsの両方を適用 */
}

selector5 {
  animation-fill-mode: none[,<fill-mode>[,...]]; /* 複数指定の場合はカンマで区切る */
}

こちらもまずはデモをご覧ください。

codepen.io

「start」ボタンをクリックすると1秒後にアニメーションが実行されます(今回はアニメーション開始前の状態を見る必要があるので、1秒置いています)。 つまりクリックしてから1秒経つまではアニメーション開始前とみなしてください。

基本のアニメーションは下記になります。

  1. 透明な状態(非表示)
  2. 徐々に不透明になりながら右に500px動く
  3. 左に250px動いて完全に不透明になる

demo1ではanimation-fill-modeは初期値のnoneのため、アニメーションが開始されてから透明な状態になります。終了後は元の状態に戻ります。

demo2ではforwardsを指定しています。アニメーション終了後、元の状態には戻らず@keyframesでのスタイルを維持します。

demo3ではbackwardsを指定しています。アニメーション開始前、@keyframesのスタイルを適用します。終了後は元の状態に戻ります。

demo4ではbothを指定しています。forwardsbackwardsの両方を適用しますので、開始前/終了後ともに@keyframesのスタイルを維持します。
一番利用頻度が高いプロパティ値かと思います。

※注意点
animation-directionreverseもしくはalternate-reverseの場合、最初のアニメーションの実行が逆方向になるので@keyframesのアニメーションが100%→0%になると説明しました。
その状態で、animation-fill-modebackwardsもしくはbothにしている場合、私は、アニメーション開始前は@keyframesの100%のスタイル(デモの場合、初期状態から見ると右に250pxの位置にいる)が適用されるのかと思ったのですが、実際確認してみると0%のスタイルが適用され、アニメーション開始されると100%からスタートします。

codepen.io

ややこしいのですが、つまり、animation-directionの指定は、アニメーションの開始前には影響がないと考えるとよいでしょう。

animation-play-state

アニメーションの一時停止/再生を設定。
また、この値を取得することでアニメーションが停止中か実行中かを判断することが可能。

selector1 {
  animation-play-state: running; /* 初期値。アニメーション実行中を示します。また停止中であった場合は実行させます */
}
selector2 {
  animation-play-state: paused; /* アニメーション停止中を示します。また実行中であった場合はその場で一時停止させます */
}

▼デモ codepen.io

demo1では初期状態をanimation-play-state: runnig;を設定しているので最初からアニメーションが実行されています。
demo2では反対にanimation-play-state: paused;にしているためアニメーションが実行されていませんが、@keyframesの最初のスタイルが適用されているのが確認できます。

それぞれ「running」「paused」のボタンをクリックするとアニメーションの再生/一時停止が実行されます。   クリックするたびに、アニメーションが適用されている.boxのanimation-play-stateプロパティの値を取得してその値を「現在アニメーションは」の次に赤字で表示させています。

※問題点
かなり便利なプロパティではあるのですが、私が確認したところだと、iOS(10.1.1)で上記のデモを確認すると「running」「paused」ボタンをクリック(タップ)してもアニメーションが再生/一時停止されませんでした。
ただ、赤字のテキストは切り替わっているので、値は切り替わっているようです。
検索して調べたところstack overflowでもその問題が報告されていました。(css animation-play-state paused doesn't work in ios [duplicate]
解決方法も少し遠回りな気がするので、使用には気を付けたほうがよさそうです。

animation

上記サブプロパティをまとめて記述できるショートハンドプロパティ。
最低限必要になるのは@keyframesの名称とアニメーション完了までの時間を表すanimation-durationです。
省略したプロパティは初期値が設定されます。
簡単に記述できるので最もよく使用します。

selector1 {
  animation: <keyframesName> 1s; /* 実質、最低限必要な記述。1秒間アニメーションが実行される */
}
selector2 {
  animation: <keyframesName> 1s ease-in .5s infinite alternate both running; /* すべてのプロパティを記述した場合 */
}

transitionの時と同じく記述の順番には少し注意が必要です。
時間をひとつ入力した場合はanimation-durationと見なされます。animation-delayを指定したい場合は必ず時間を2つ入力する必要があります。

@keyframesの書き方

下記はそれぞれ違う書き方ですが同じ動きをします。

@keyframes anim1 {
    0% {
        transform: translateX(0);
    }
    50% {
        transform: translateX(500px);
    }
    100% {
        transform: translateX(0);
    }
}

/* 途中のキーフレームのみ記述 */
@keyframes anim2 {
    50% {
        transform: translateX(500px);
    }
}

/* 同じスタイルのフレームはカンマ区切りでまとめて記述できる */
@keyframes anim3 {
    0%,
    100% {
        transform: translateX(0);
    }
    50% {
        transform: translateX(500px);
    }
}

▼デモ

codepen.io

しかし個人的には一番最初のanim1の記述をおすすめします。
あとでコードを見返したときに頭の中で動きを想像しやすい上、修正などもしやすいからです。

anim2の場合、開始と終了を明示していません。
この場合、最初から.boxtransform: translateX(100px);などの指定があった場合、その地点から500pxまで移動してまた100pxまで戻ります。
この特性を生かせば柔軟なアニメーションの作成ができそうですが、この特性を理解しないと意図しない動きになりえるので要注意です。

animationのイベント

アニメーションのイベントをJavaScriptで取得することが可能です。
利用にはベンダープレフィックスwebkitを付けたほうがよいでしょう。
IE10にはMSも付けたほうが良さそうです。(参考:Animation iteration event) イベントの種類は以下の3つです。

  • animationstart アニメーション開始のイベントを取得。
  • animationiteration アニメーション実行中のイベントを取得。
  • animationend アニメーション終了のイベントを取得。

▼デモ codepen.io

animationiterationイベントはanimation-iteration-count2以上つまり複数回アニメーションが実行されるときに発生します。1回のみのアニメーションでは発生しません。

animationendイベントはanimation-iteration-countinfiniteつまり無限回実行のときは発生しません。

まとめ

  • プロパティの数が多いので、基本的にショートハンドのanimationを利用する。
  • animation-directionではreverse系の逆再生の動きの時はイージングも逆になる。
  • animation-directionの指定はアニメーション開始前には影響がない。
  • animation-play-stateiOSでの挙動に注意。
  • @keyframesでは原則、開始点(0%)と終了点(100%)を明示する。
  • @keyframesでは、キーフレームごとにanimation-timing-functionの再定義が可能。

※参考記事は、次回の発展編の最後にまとめてご紹介します。