HTML5 × CSS3 × jQueryを真面目に勉強 – #9.1 CSS3アニメーション(Animation)

2012.11.15

そんな訳で、前回の記事でCSS3 Transitionについて学んだので、CSS3 Animationについて学んだことについてもここらでまとめておくとします。

はじめに

Transitionは対象となる要素の始点終点の状態をそれぞれ定義して、スムーズに変化させるという機能でした。

対するAnimationは、始点と終点の間にキーフレームを配置してその時点ごとの状態をそれぞれ指定し、よりダイナミックなアニメーションが実現できます。

Animation - アニメーション

Animationプロパティの詳細は、コチラのサイトにて非常に分かりやすく的確にまとまっているので、当ブログでは特別な要点以外は割愛します。

Animationプロパティでは、以下の7つの項目をまとめて指定することが出来ます。

animation
animation-name 実行するアニメーション(@keyframes)の名前
animation-duration アニメーションにかかる時間
animation-timing-function アニメーションのタイミングやどのように進行するかを指定 (イージング)
animation-delay アニメーションが開始されるまでの時間 (遅延時間)
animation-iteration-count アニメーションの繰り返し回数
animation-direction アニメーションの再生方向
animation-fill-mode アニメーションの実行前と実行後に適用するスタイル

animation-nameは、実際にどのような動きをするかを定義した@keyframesを指定し、唯一の必須項目です。

記述例) animation

/*
 * @animation-name
 * @animation-duration
 * @animation-timing-function
 * @animation-delay
 * @animation-iteration-count
 * @animation-direction
 * @animation-fill-mode
 */
animation: myAnimarion 1s ease 0s 1 normal none;

animation-name以外のプロパティは全てオプション扱いとなり、省略した場合は記述例にある値が初期値として指定されます。

@keyframes

@keyframesは、要素に対してどのようなアニメーションをするのかというのを定義したもので、プログラミングでいう関数に扱いが似ています。

アニメーションの始点をfrom(もしくは0%)で指定し、終点をto(もしくは100%)で指定します。これだけではTransitionと同じですが、0%と100%の間に25%、50%、80%と細かくキーフレームを配置して、それぞれに要素の状態を定義することが出来ます。

記述例) @keyframes

@keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}

%でキーフレームを配置し、それぞれのブロック内にそのタイミングの状態を指定します。ブロック内は通常のCSSと同じように記述します。

当記事執筆時点(2012年11月)では、transitionプロパティやanimationプロパティと同様にベンダープレフィックスが必要になります。

ベンダープレフィックスをつけてみた) @keyframes

@-webkit-keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}
@-moz-keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}
@-o-keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}
@-ms-keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}
@keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { background-color: #ccff00; width: 100%}
  50%  { background-color: #4d4d4d; height: 50%;}
  100% { background-color: #fdcf00; }
}

Animation 事始め

マウスオーバー時にdiv要素をアニメーションで変形させてみます。いくつかのキーフレームを配置し、段階的に色々と変化させてみます。

※ベンダープレフィックスは省略していますが、実際のコードでは必要となります。

div {
  background: #fff;
  box-shadow: 0 20px 40px #888888;
  height: 170px;
  margin: 60px auto;
  padding: 15px;
  width: 170px;
}
  div p {
    line-height: 170px;
    margin: 0;
    text-align: center;
  }
  div:hover {
    animation: myAnimation 3s linear both;
  }

@keyframes myAnimation {
  0%   { background-color: #e61374; }
  25%  { border-radius: 50%; }
  50%  { background-color: #ccff00; border-radius: 50%; transform: scale(1, 1); }
  100% { border-radius: 50%; transform: scale(100, 0); } }

いくつかプロパティが指定されていますが、ここではbackground-colorに着目します。
まずアニメーション開始時に#e61374が適用されます。そこから次の背景色が指定されている50%のキーフレームに向けて色が変化していきます。その先のキーフレーム(100%)では背景色が指定されていないので、初期値である#fffに変化していきます。

animation-fill-mode

簡単に言うと、アニメーションの実行前と実行後はどのような状態にしておくかを指定するプロパティです。

animation-fill-modeで指定できるプロパティは、以下の4種類です。

animation-fill-mode
none 実行前の遅延時間と実行後はアニメーション呼出前の状態となる
※初期値
forwards 実行後の状態がアニメーション終了時の状態(100%)で保持される
backwards 実行前の遅延時間の間、アニメーション開始時の状態(0%)で保持される
both forwardsとbackwardsの両方が適用される。

CSS3 の機能を活かしたプリローダーを作ってみる

JavaScriptに一切頼らずに、CSSだけでプリローダー風のアニメーションを作ってみることにします。

完成イメージはこんな感じです。

ではひとつずつ実装していきます。

1 | HTMLコードを作成

preloader.html

<body>
  <h1>Preloader | CSS3 animation</h1>

  <ul class="preloader">
    <li id="pointStart" class="point">
      <span class="inner-point"></span>
      <span class="pulse"></span>
    </li>
    <li class="line">
      <span class="inner-line"></span>
    </li>
    <li id="pointEnd" class="point">
      <span class="inner-point"></span>
      <span class="pulse"></span>
    </li>
  </ul>
</body>

プリローダーの始点と終点のポイント、および二点間を結ぶラインをlist要素で定義します。ポイントは核とパルスをそれぞれ表現する為にspan要素でそれぞれ定義したものをネストします。

2 | CSSの実装 - ポイント

.preloader {
  margin: 40px auto;
  width: 640px;
}
  .preloader li {
    float: left;
    position: relative;
  }

/*---------- point and pulse ----------*/
.point {
  height: 20px;
  position: relative;
  width: 20px;
}
  .point .inner-point {
    border-radius: 50%;
    display: block;
    height: 100%;
    width: 100%;
    background-image: -webkit-linear-gradient(90deg, #2187e7, #a0eaff);
    background-image: -moz-linear-gradient(90deg, #2187e7, #a0eaff);
    background-image: -o-linear-gradient(90deg, #2187e7, #a0eaff);
    background-image: linear-gradient(90deg, #2187e7, #a0eaff);
  }
  .point .pulse {
    border: 2px solid #24b9c6;
    border-radius: 50%;
    box-shadow: 0 0 10px 5px #24b9c6;
    display: block;
    height: 100%;
    left: -2px;
    position: absolute;
    top: -2px;
    width: 100%;
  }

はじめにpreloaderの子要素をfloatプロパティで横並びにします。次にポイントのスタイルを作ります。inner-point要素に円形のスタイルを適用し、pulse要素はポイントを囲むような光の輪にします。

3 | CSSの実装 - ライン

/*---------- line ----------*/
.line {
  width: 600px;
}
  .line .inner-line {
    background: #2187e7;
    box-shadow: 0 0 10px 5px rgba(0, 198, 255, 0.5);
    display: block;
    height: 1px;
    margin: 10px 0;
    width: 100%;
  }

line要素はラインのいわゆるコンテナであり、inner-line要素はゲージに相当します。

ここまでで基本的な見栄えはできました。

4 | アニメーションの実装 - 初期値

ポイントおよびパルスの初期状態を指定します。

/*---------- point and pulse ----------*/
・
・
・
  .point .inner-point, .point .pulse {
    -webkit-transform: scale(0, 0);
    -moz-transform:    scale(0, 0);
    -ms-transform:     scale(0, 0);
    -o-transform:      scale(0, 0);
    transform:         scale(0, 0);
  }
・
・
・

同様にラインの初期状態を指定します。

※ハイライト部分を変更

/*---------- line ----------*/
.line {
  width: 600px;
}
  .line .inner-line {
    background: #2187e7;
    box-shadow: 0 0 10px 5px rgba(0, 198, 255, 0.5);
    display: block;
    height: 1px;
    margin: 10px 0;
    width: 0;
  }

それぞれの要素がアニメーションで表示されるので、初期状態はtransform:scale()を使ったり、widthを0にするなどして非常時状態にしておきます。ブラウザで確認してみると何も表示されなくなっているかと思います。

5 | アニメーションの実装 - キーフレームアニメーション

ポイントのアニメーションを定義します。

/* animation
 ----------------------------------------*/
/*---------- point ----------*/
@-webkit-keyframes point {
  0%   { -webkit-transform: scale(0, 0); }
  100% { -webkit-transform: scale(1, 1); }
}

@-moz-keyframes point {
  0%   { -moz-transform: scale(0, 0); }
  100% { -moz-transform: scale(1, 1); }
}

@-ms-keyframes point {
  0%   { -ms-transform: scale(0, 0); }
  100% { -ms-transform: scale(1, 1); }
}

@keyframes point {
  0%   { transform: scale(0, 0); }
  100% { transform: scale(1, 1); }
}

続いてパルスのアニメーションも定義します。

/*---------- pulse ----------*/
@-webkit-keyframes pulse {
  0%   { -webkit-transform: scale(0, 0);       opacity: 0; }
  10%  { -webkit-transform: scale(1, 1);       opacity: .5; }
  50%  { -webkit-transform: scale(1.75, 1.75); opacity: 0; }
  100% { -webkit-transform: scale(0, 0);       opacity: 0; }
}

@-moz-keyframes pulse {
  0%   { -moz-transform: scale(0, 0);       opacity: 0; }
  10%  { -moz-transform: scale(1, 1);       opacity: .5; }
  50%  { -moz-transform: scale(1.75, 1.75); opacity: 0; }
  100% { -moz-transform: scale(0, 0);       opacity: 0; }
}

@-ms-keyframes pulse {
  0%   { -ms-transform: scale(0, 0);       opacity: 0; }
  10%  { -ms-transform: scale(1, 1);       opacity: .5; }
  50%  { -ms-transform: scale(1.75, 1.75); opacity: 0; }
  100% { -ms-transform: scale(0, 0);       opacity: 0; }
}

@keyframes pulse {
  0%   { transform: scale(0, 0);       opacity: 0; }
  10%  { transform: scale(1, 1);       opacity: .5; }
  50%  { transform: scale(1.75, 1.75); opacity: 0; }
  100% { transform: scale(0, 0);       opacity: 0; }
}

アタマ光がパーンと弾けるようなイメージで動きを指定します。

最後にラインのアニメーションを定義します。

/*---------- line moves ----------*/
@-webkit-keyframes move {
  0%   { width: 0; }
  100% { width: 100%; box-shadow: 0 0 10 5px rgba(0, 198, 255, 0.5); } }

@-moz-keyframes move {
  0%   { width: 0; }
  100% { width: 100%; box-shadow: 0 0 10 5px rgba(0, 198, 255, 0.5); }
}

@-ms-keyframes move {
  0%   { width: 0; }
  100% { width: 100%; box-shadow: 0 0 10 5px rgba(0, 198, 255, 0.5); }
}

@keyframes move {
  0%   { width: 0; }
  100% { width: 100%; box-shadow: 0 0 10 5px rgba(0, 198, 255, 0.5); }
}

これでアニメーションの定義が一通りできました。

6 | アニメーションの実装 - 呼び出し

各要素に対してアニメーション呼び出しの処理を追記していきます。

#pointStart .inner-point {
  -webkit-animation: point 0.1s linear 0s 1 normal forwards;
  -moz-animation:    point 0.1s linear 0s 1 normal forwards;
  -o-animation:      point 0.1s linear 0s 1 normal forwards;
  -ms-animation:     point 0.1s linear 0s 1 normal forwards;
  animation:         point 0.1s linear 0s 1 normal forwards;
}
#pointStart .pulse {
  -webkit-animation: pulse 1s ease-out 0s 1 normal none;
  -moz-animation:    pulse 1s ease-out 0s 1 normal none;
  -o-animation:      pulse 1s ease-out 0s 1 normal none;
  -ms-animation:     pulse 1s ease-out 0s 1 normal none;
  animation:         pulse 1s ease-out 0s 1 normal none;
}

#pointEnd .inner-point {
  -webkit-animation: point 0.1s linear 3.05s 1 normal forwards;
  -moz-animation:    point 0.1s linear 3.05s 1 normal forwards;
  -o-animation:      point 0.1s linear 3.05s 1 normal forwards;
  -ms-animation:     point 0.1s linear 3.05s 1 normal forwards;
  animation:         point 0.1s linear 3.05s 1 normal forwards;
}
#pointEnd .pulse {
  -webkit-animation: pulse 1s ease-out 3.05s infinite normal forwards;
  -moz-animation:    pulse 1s ease-out 3.05s infinite normal forwards;
  -o-animation:      pulse 1s ease-out 3.05s infinite normal forwards;
  -ms-animation:     pulse 1s ease-out 3.05s infinite normal forwards;
  animation:         pulse 1s ease-out 3.05s infinite normal forwards;
}

始点と終点のポイントのアニメーション呼び出しを指定しました。終点の方はラインのアニメーションが終わったタイミングで開始させるために遅延時間を指定しています。
※本来はJavaScriptを使って動的に制御するのがベターですが、今回はあくまでサンプルということで、あえてこのように書きましたよ、と。

ラインのアニメーション呼び出しを追記します。

※ハイライト部分を追加

/*---------- line ----------*/
  .line .inner-line {
    background: #2187e7;
    box-shadow: 0 0 10px 5px rgba(0, 198, 255, 0.5);
    display: block;
    height: 1px;
    margin: 10px 0;
    width: 100%;
    -webkit-transform: scaleX(0);
    -moz-transform: scaleX(0);
    -ms-transform: scaleX(0);
    -o-transform: scaleX(0);
    transform: scaleX(0);
    -webkit-animation: move 3s linear 0s 1 normal forwards;
    -moz-animation:    move 3s linear 0s 1 normal forwards;
    -o-animation:      move 3s linear 0s 1 normal forwards;
    -ms-animation:     move 3s linear 0s 1 normal forwards;
    animation:         move 3s linear 0s 1 normal forwards;
  }

これで完成です。以下のリンクよりデモをご覧いただけます。

おわりに

レガシーなブラウザをサポートしなくてはならない状況においては、アニメーションの実装はJavaScriptに頼らざるを得ません。仮にモダンブラウザのみに的を絞った状況においても、コードの記述に独特のクセがあるからなのかCSS3アニメーションでなく、慣れ親しんだJavaScriptによるアニメーション実装がなされているという傾向も未だにあるかと思います。

CSS3アニメーションは、Webkit系ブラウザではJavaScriptと比較しても遜色ない滑らかな動きを実現しますが、Firefoxではいささか動きにもたつきが見られたり、IEはVer.10以降でなければそもそも動かないなど、まだまだ発展途上の段階にいます。

ですが要素の状態を定義するという意味では、やはりアニメーションをCSSで定義するというのは理屈が通っていますし、パフォーマンスの観点からも使える場面では積極的に活用するべきです。主要ブラウザ全般で一律に使えるようになるのはいつになるかサッパリ分かりませんが、そのときに備えて学習の歩を進めていくのがよろしいかと思います。

いまからでも遅くないです。

参考サイト