TECHNICAL BLOG

2020/11/20 # フロントエンド # 入門 # CSS 2020/11 初心者のためのCSSアニメーション入門

こんにちは、大阪事業所所属の瀬戸です。今回は、ずっと苦手意識のあったCSSアニメーションについて自分で調べてわかったことや、上長に質問して理解できたことを、簡単にまとめようと思います。

「HTMLやCSSを書くことには慣れてきたけど、アニメーションは全然わからない...」「トランジションとCSSアニメーションはどう違うの?使い分けは?」など、アニメーションに苦手意識を持った人の助けになれば幸いです。

トランジション と アニメーション

CSSでアニメーションを実装するには、CSS TransitionCSS Animation の2種類があります。イメージとしては、CSS Transition はお手軽アニメーション、CSS Animation は本格アニメーションという感じです。両者の使い分けについてはあとで解説しますので、先にCSS Transitionについて見ていきます。

CSS Transition

Transitionは英語で「移行」を意味しますが、CSS Transitionはプロパティの変更を検知し、変化前の状態から一定時間で緩やかに見た目を変化させることができます。変化していく途中の状態を細かく指定することはできません。後述するトランジションのプロパティの指定に合わせて、CSSがよしなにアニメーションしてくれます。

CSS Transitionでは以下のプロパティを使って、アニメーションを実装していきます。

  • transition-duration
  • transition-property
  • transition-timing-function
  • transition-delay
  • transition

transition-duration

アニメーション開始から終了までにかかる時間を指定します。指定できる単位はs(秒)、ms(ミリ秒)です。
初期値は0ですが、この場合はアニメーションは発生せず、すぐに変更が適用されます。

<div class="box"><div>
.box{
    background-color: yellow;
    height: 100px;
    /* 変化前の幅 */
    width: 200px;
    transition-duration: 2s;
}
.box:hover{
    /* 変化後の幅 */
    width: 500px;
}

transition-duration

transition-property

アニメーションを適用するプロパティを指定します。ここで指定されたプロパティのみ、トランジションが適用されます。初期値はall<code>ですが、</code>allの場合はトランジションが適用できるすべてのプロパティに作用します。
個別にプロパティを指定する場合は、トランジションを適用したいプロパティ名を書きます。複数ある場合は、カンマで区切ります。

widthのみ指定
<div class="box1"></div>

width, heightを指定
<div class="box2"></div>

all
<div class="box3"></div>
div {
    margin-bottom: 1rem;
    width: 100px;
    height: 100px;
    background-color: yellow;
    transition-duration: 2s;
}
div:hover{
    width: 500px;
    height: 200px;
    background-color: orange;
}
.box1 {
    transition-property: width;
}
.box2 {
    transition-property: width, height;
}
.box3 {
    transition-property: all;
}

transition-property

それぞれ指定したプロパティにのみアニメーションが適用され、それ以外のプロパティは瞬時に変更が適用されていることがわかると思います。

transition-timing-function

だんだん早くなるのか、最初と最後はゆっくりになるのかなど、どのように変化していくのか、その変化の具合(イージング)を指定します。イージングの変化の仕方は大きく分けて以下の4つです。

  • linear : 等速で変化する
  • ease-in : 徐々に加速する
  • ease-out : 徐々に減速する
  • ease-in-out : 加速してから減速する

イージングを指定するときは以下のサイトが参考になるかと思います。

イージング関数チートシート
https://easings.net/ja

transition-timing-function

transition-delay

変化が始まるまでの時間を指定します。transition-duration<code>と同様に、単位は s(秒)、ms(ミリ秒)が使えます。</code>0s<code>もしくは</code>0msのときはプロパティの変更を検知するとすぐにアニメーションが始まります。

1秒後にアニメーション
<div class="box"></div>
.box {
    width: 100px;
    height: 100px;
    background-color: yellow;
    transition-duration: 2s;
    transition-delay: 1s;
}
.box:hover{
    width: 500px;
}

transition-delay

transition

transitionプロパティは、上記4つのプロパティをまとめて指定できるショートハンドプロパティです。
transition-property<code>, </code>transition-duration<code>, </code>transition-timing-function<code>, </code>transition-delayの順番で記述します。

transition: width 1s;
transition: width 1s ease-in;
transition: width 1s ease-in 0.5s;

Q. 変化前と変化後、どっちに指定するの?

両方とも指定できます。ただし、変化前にtransition<code>を指定した場合と、変化後に</code>transitionを指定した場合で少し挙動が異なります。

変化前にtransition
<div class="box1"></div>

変化後にtransition
<div class="box2"></div>
div {
    height: 100px;
    background-color: yellow;
    margin-bottom: 1rem;
}
.box1 {
    width: 100px;
    transition: width 2s;
}
.box1:hover {
    width: 500px;
}
.box2 {
    width: 100px;
}
.box2:hover {
    width: 500px;
    transition: width 2s;
}

before-after

この例を見ていただくと、幅が広がるときはどちらも全く同じ変化の仕方ですが、元に戻るときのアニメーションが異なります。

変化前にtransitionを指定したほうは元に戻るときもアニメーションされますが、変化後にtransitionを指定したほうは元に戻るときにアニメーションが適用されず、一瞬で元の状態に戻ります。

Q. どうやってアニメーションを発生させるの?

:hoverなどの擬似セレクタを使う方法と、JavaScriptでクラスの付け替えをする方法があります。これにより、ユーザーの操作によってプロパティの変更を検知し、アニメーションさせることができます。

擬似セレクタ(hover)
<div class="box1"></div>

JavaScriptでクラスの付与・削除
<div id="box2" class="box2"></div>
const box2 = document.getElementById('box2');
box2.addEventListener('click', () => {
    if(box2.classList.contains('big')){
        box2.classList.remove('big');
    }else{
        box2.classList.add('big');
    }
})
div {
    background-color: yellow;
    margin-bottom: 1rem;
}
.box1 {
    width: 100px;
    height: 100px;
    transition: all 2s;
}
/* 変化後の状態 */
.box1:hover {
    width: 200px;
    height: 200px;
}
.box2 {
    width: 100px;
    height: 100px;
    transition: all 2s;
}
/* 変化後の状態 */
.big {
    width: 200px;
    height: 200px;
}

transition_start

パッと見はわかりにくいですが、上の例はマウスを要素にhoverすることでアニメーションが発生しています。下の例は、要素をクリックするたびにJavaScriptでbigクラスを付与・削除しています。
こうすることでアニメーションを発生させることはできますが、この例のように、transition<code>もしくは</code>transition-propertyで指定したプロパティがどう変わるのかを指定しなければアニメーションが発生しないので注意です。

CSS Animation

CSS Animation は CSS Transition よりも細かいアニメーションの設定が可能です。CSS Transitionではhoverやクラスの追加・削除などのアニメーション開始のきっかけが必要でしたが、CSS Animationの場合はきっかけがなくてもアニメーションさせることができます。つまり、読み込み後すぐにアニメーションが発生します。

CSSアニメーションは2つの要素で構成されています。一つはCSS Transitionと同じようにアニメーション時間、変化速度など、アニメーションについて記述する部分で、もう一つはスタイルの指定です。

CSS Animation では、アニメーションの指定をする前に@keyframesを使用して任意の地点でのスタイルを定義(キーフレームアニメーションと言います)しておく必要があります。

@keyframes scale {
    0% {
        width: 100px;
    }
    50% {
        width: 400px;
    }
    100% {
        width: 300px;
    }
}

@keyframes<code>の横に</code>scaleとありますが、これはこのアニメーションの名前です。変数を定義するような感覚です。
この例では、アニメーション開始時の幅が100px、半分の時間が経過したタイミングでの幅が400px、終了時の幅が300pxとなるよう定義しています。しかし、これだけだと特定のタイミング(キーフレーム)でのスタイルを定義しただけなので、まだアニメーションはできません。

これをアニメーションさせるためには、以下のプロパティを使用してどのようにアニメーションさせるかを指定します。

  • animation-name
  • animation-duration
  • animation-timing-function
  • animation-delay
  • animation-iteration-count
  • animation-direction
  • animation-fill-mode
  • animation-play-state
  • animation

CSS Transition でも似たようなプロパティがありますが、使い方は大体同じです。ここではそれ以外のプロパティについて説明していこうと思います。

animation-name

animation-name<code>は、</code>@keyframesで定義したアニメーションの名前を指定します。

animation-name: scale;

animation-iteration-count

CSS Transition では、プロパティの変更があったときの1回だけしかアニメーションが発生しません。しかし、CSS Animation は何回実行するかを指定することができます。初期値は1です。
無限に実行したい場合は、値にinfiniteを指定します。

1回
<div class="box1"></div>

3回
<div class="box2"></div>

∞回(infiniteを指定)
<div class="box3"></div>
div {
    background-color: yellow;
    margin-bottom: 1rem;
    width: 100px;
    height: 100px;
    animation-name: scale;
    animation-duration: 3s;
}
.box1 {
    animation-iteration-count: 1;
}
.box2 {
    animation-iteration-count: 3;
}
.box3 {
    animation-iteration-count: infinite;
}

animation-iteration-count

上のgif画像は5回ループしたら最初から再生されるようになっています。animation-iteration-countの指定によるものではないのでお気をつけください。

animation-direction

animation-directionは、アニメーションの再生方向を指定することができます。再生方向は以下の4通りです。

  • normal:毎回順方向で再生
  • reverse:毎回逆方向から再生
  • alternate:順方向から始まり、順方向と逆方向を交互に繰り返す
  • alternate-reverse:逆方向から始まり、逆方向と順方向を交互に繰り返す

animation-direction

animation-fill-mode

アニメーション開始前と終了後に、@keyframesで指定したプロパティを適用するかどうかを指定します。

・none:開始前、終了後にはアニメーションのスタイルは適用されない(初期値)
・forwards:終了後は終了時のスタイルを適用
・backwards:開始前に開始時のスタイルを適用
・both:開始前には開始時のスタイル、終了後は終了時のスタイルを適用

none
<div class="box1"></div>

forwards
<div class="box2"></div>

backwards
<div class="box3"></div>

both
<div class="box4"></div>
div {
    background-color: yellow;
    margin-bottom: 1rem;
    width: 200px;
    height: 100px;
    animation-name: scale;
    animation-duration: 3s;
    animation-delay: 3s;
}
.box1 {
    animation-fill-mode: none;
}
.box2 {
    animation-fill-mode: forwards;
}
.box3 {
    animation-fill-mode: backwards;
}
.box4 {
    animation-fill-mode: both;
}

animation-fill-mode

開始前、終了後にどの時点のスタイルが適用されているかわかりやすいよう、あえて色も変えています。

animation-play-state

animation-play-state<code>は、アニメーションが実行中か停止中かを指定します。</code>running<code>の場合は実行し、</code>paused<code>の場合は停止します。</code>paused<code>から</code>runningに切り替わる場合は停止したところから再開します。

<div class="running" id="box"></div>

<button id="button">一時停止</button>
const button = document.getElementById('button');
button.addEventListener('click', ()=>{

    const box = document.getElementById('box');
    if(box.classList.contains('running')){
        box.classList.remove('running');
        box.classList.add('paused')
        button.innerText = '再生する';
    }else{
        box.classList.remove('paused');
        box.classList.add('running')
        button.innerText = '一時停止';
    }
})
div {
    background-color: yellow;
    margin-bottom: 1rem;
    width: 100px;
    height: 100px;
    animation-name: scale;
    animation-duration: 3s;
    animation-iteration-count: infinite;
}
.running {
    animation-play-state: running;
}
.paused {
    animation-play-state: paused;
}

animation-play-state

animation

animation<code>はこれまでのプロパティをまとめて指定できる、ショートハンドプロパティです。</code>transition<code>とは違い各プロパティは順不同で指定できます。ただ、</code>animation-duration<code>と</code>animation-delay<code>は両方とも秒数を指定するので、最初に指定されたほうが</code>animation-durationの秒数として解釈されます。

Q. CSS Transition と CSS Animation の使い分けは?

シンプルなアニメーションであれば CSS Transition、少し凝ったアニメーションにしたい場合は CSS Animationを使います。
ただ、シンプルなアニメーションであっても、フェードインのように同じアニメーションがいろいろなところで必要な場合は、CSS Animationでアニメーションを定義しておいた方が楽になる場合もあります。

Q. JavaScriptのアニメーションは?

まずはCSS Transitionで実装できないか検討してみて、それがダメだったらCSS Animation、それでも難しい場合や、よりリッチなWebサイトを作り込みたいときはJavaScriptも使う、という感じで作っていくのがいいかと思います。

Q. どこでどんなアニメーションをいれたらいいかわからない!

アニメーションは、基本的にはユーザーの操作に対するフィードバックが目的です。視覚的な動きを取り入れることにより、今どんな状態なのか、どんな変化が起きたのかをよりわかりやすくユーザーに伝えることができます。
UIを考える上で大切な基本原則については、以下のサイトにわかりやすくまとめられています

モバイルアプリのUI設計に大切な、7つの基本アニメーションまとめ
https://photoshopvip.net/88490

まとめ

僕自身が学習する上でつまづいたポイントも盛り込んでみましたが、いかがだったでしょうか。これからアニメーションについて学習する人は、まずは CSS Transition に慣れることをおすすめします。少しでもアニメーション学習の助けになれば幸いです。