CSSによるアニメーション(CSS Transition、CSS Animation)

## CSS TransitionとCSS Animationの違い

CSSによるアニメーションには、CSS TransitionとCSS Animationの2種類があります。

|項目|CSS Transition|CSS Animation|
|---|---|---|
|プロパティの変化|単純なもののみ対応可能|複雑なものも対応可能|
|ループ|不可|可|
|変化前の状態に戻る時|アニメーションあり|アニメーションなし|


## 使い分け
### CSS Transitionの用途の例

- メニューのスライドインアウト
- ホバー時のプロパティ変化

### CSS Animationの用途の例

- ローディングアニメ
- 複雑なプロパティの変化

### CSSで対応できないアニメーションの例

- バウンド
- 停止、一時停止
- 巻き戻し
- スローダウンなど速度の変化
 
より高度な効果を実現したい場合は、CSSアニメーションだけでは対応できないのでJavaScriptアニメーションを使います。

## アニメーションのパフォーマンス
LayoutとPaintに影響を与えるCSSプロパティの変更はレンダリングコストが高いので、アニメーションの品質劣化に繋がります。

### Layoutに影響を与えるCSSプロパティ
display, width, height, left, topなど

### Paintに影響を与えるCSSプロパティ
border-radius, background-colorなど

### LayoutやPaintに影響を与えない
transformなど


## CSS Transition

### CSS Transition開始のきっかけを作る
CSS Transitionでのアニメーションには、動作のきっかけが必要です。
:hoverなどの疑似クラスや、JavaScriptでのクラスの着脱がよく使われます。

#### 疑似クラスを使う場合の例
例：ボックスにマウスを乗せると色が変わり、外すと色が戻るアニメーション

```:html
 <div class="box"></div>
```

```:css
.box{
  background-color: #e74c3c;
  width: 100px;
  height: 100px;
  transition: background-color 500ms ease-in-out;
}
 
.box:hover{
    background-color: #2ecc71;
}
```

#### クラスの着脱を使う場合の例
例：動作ボタンを押すとボックスが右へ移動し、再度押すと元の位置へ戻るアニメーション

```:html
<div class="box" id="js-moveTarget"></div>
<button id="js-moveSwitch">動作ボタン</button>
```

```:css
.box{
  background-color: #e74c3c;
  width: 100px;
  height: 100px;
  transition: transform 500ms 0s ease-in-out;
}

.box.active{
  transform: translateX(500px);
}
```

```:js
const moveTarget = document.getElementById("js-moveTarget");
const moveSwitch = document.getElementById("js-moveSwitch");
const moveAction = ()=>{
    moveTarget.classList.toggle("active");
}
moveSwitch.addEventListener("click",moveAction);
```


### CSS Transitionで利用できるプロパティ

|プロパティ||
|---|---|
|transition|下4つをまとめて指定可能|
|transition-property|どのプロパティにアニメーションを適用するか指定する(all/none/プロパティ名)|
|transition-duration|アニメーション開始から終了までの時間を指定する(単位はs、ms)|
|transition-delay|アニメーションが開始するまでの時間を指定する(単位はs、ms)|
|transition-timing-function|アニメーションのイージングを指定する|
※transition-propertyは意図しない動きを避けるために、allではなく、カンマ区切りでプロパティ名を列記する方が安全です。

#### transitionプロパティでまとめて指定する場合

```:css
/* transition: transition-propertyの値 transition-durationの値 transition-delayの値 transition-timing-functionの値 */
transition: all 300ms 0s ease;
```

#### transition-timing-functionの値

|値|内容|cubic-bezierで表現すると|
|---|---|---|
|ease|開始と完了を滑らかにする(初期値)|cubic-bezier(0.25, 0.1, 0.25, 1.0)|
|linear|一定速度|cubic-bezier(0.0, 0.0, 1.0, 1.0) |
|ease-in|ゆっくり始まる|cubic-bezier(0.42, 0, 1.0, 1.0)|
|ease-out|ゆっくり終わる|cubic-bezier(0, 0, 0.58, 1.0) |
|ease-in-out|ゆっくり始まってゆっくり終わる|cubic-bezier(0.42, 0, 0.58, 1.0) |
|cubic-bezier|指定による|-|


##### cubic-bezierの指定方法
```:css
/* cubic-bezier(x1, y1, x2, y2); */
cubic-bezier(0.42, 0, 0.58, 1.0);
```
Chrome DevToolsのcubic-bezierの前のアイコンをクリックすると、設定したイージングの動きを見ながら調整できて便利です。


#### transition-timing-functionの値(コマ送り)

|値|内容|steps(n,start/end)で表現すると|
|---|---|---|
|step-start|アニメーション開始直後に完了状態になりそのままキープ|steps(1, start)|
|step-end|アニメーションが完了するまで初期状態で、完了時にいきなり完了状態になる|steps(1, end)|
|steps(n, start)|step-startをn(任意の数)で分割してコマ送りアニメーション|-|
|steps(n, end)|step-endをn(任意の数)で分割してコマ送りアニメーション|-|

steps()の指定方法

```:css
transition-timing-function: steps(10,start);
```


### CSS Transitionのイベントを取得する

|Transitionのイベント|発生タイミング|
|---|---|
|transitioncancel|CSS Transtionのキャンセル時|
|transitionend |CSS Transtionが完了時|
|transitionrun|transition-delay開始時|
|transitionstart|transition-delayの終了時|


```:js
moveTarget.addEventListener('transitioncancel', () => {
  console.log('Transitionがキャンセルされました。');
});

moveTarget.addEventListener('transitionend', () => {
  console.log('Transitionが完了しました。');
});

moveTarget.addEventListener('transitionstart', () => {
  console.log('Transitionが始まりました。');
});

moveTarget.addEventListener('transitionrun', () => {
  console.log('Transitionが始まります。');
});
```


#### CSS Transitionの対象プロパティが複数の場合
対象プロパティの数だけ同じイベントが発生してしまうので、取得対象プロパティを絞ります。

例：transformプロパティだけに絞った場合

```:js
moveTarget.addEventListener('transitioncancel', () => {
  if (event.propertyName == 'transform') {
  console.log('Transitionがキャンセルされました。');
  }
});

moveTarget.addEventListener('transitionend', () => {
  if (event.propertyName == 'transform') {
  console.log('Transitionが完了しました。');
  }
});

moveTarget.addEventListener('transitionstart', () => {
  if (event.propertyName == 'transform') {
  console.log('Transitionが始まりました。');
  }
});

moveTarget.addEventListener('transitionrun', () => {
  if (event.propertyName == 'transform') {
  console.log('Transitionが始まります。');
  }
});
```

## CSS Animation


### CSS Animation開始のきっかけを作る
ページのローディングアニメーションなどのように、きっかけが不要な場合もあります。

#### クラスの着脱
例：動作ボタンを押すとボックスがアニメーションのループを開始し、再度押すとアニメーションが終了して初期状態に戻るアニメーション

```:html
 <div class="box" id="js-moveTarget"></div>
 <button id="js-moveSwitch">動作ボタン</button>
```

```:css
.box{
  background-color: #e74c3c;
  width: 100px;
  height: 100px;
}

.box.active{
    animation: moveTest 4s ease-in-out 0s infinite alternate-reverse none running;
}
 
@keyframes moveTest {
  0% {
    background-color: #e74c3c;
  }

  50% {
    transform: scale(2) rotate(10deg) translateX(200px);
    background: red;
  }

  100% {
    transform: scale(1) rotate(0deg) translateX(0px);
    background-color: #2ecc71;
  }
}
```

```:js
const moveTarget = document.getElementById("js-moveTarget");
const moveSwitch = document.getElementById("js-moveSwitch");
const moveAction = ()=>{
    moveTarget.classList.toggle("active");
}
moveSwitch.addEventListener("click",moveAction);

```


### CSS Animationで利用できるプロパティ

|プロパティ|内容|
|---|---|
|animation|下記の8つのプロパティをまとめて設定できる|
|animation-name|適用するキーフレームアニメーション名を指定|
|animation-duration|アニメーション開始から終了までの時間を指定(単位はs、ms)|
|animation-timing-function|アニメーションのイージングの種類を指定|
|animation-delay|アニメーション開始までの時間を指定(単位はs、ms)|
|animation-iteration-count|アニメーションのループ回数を指定(数字/infinite)|
|animation-direction|アニメーションの再生方向を指定(normal/reverse/alternate/alternate-reverse)|
|animation-fill-mode|キーフレームアニメーションで指定したプロパティをアニメーション開始前、終了後に適用するかどうかの指定(none/forwards/backwards/both)|
|animation-play-state|アニメーションを再生中か一時停止にするかの指定(running/paused)|


#### animationプロパティでまとめて指定する場合

```:css
/* animation: animation-nameの値 animation-durationの値 animation-timing-functionの値 animation-delayの値 animation-iteration-countの値 animation-directionの値 animation-fill-modeの値 animation-play-stateの値
animation: anime1 2s ease -2s infinite alternate both running;
```

#### 複数のアニメーションを連続する場合
カンマ区切りで、複数のアニメーションを指定できます。
animation-delayを調整して、アニメーションが連続再生されるようにします。
次のアニメーションに状態を引き継ぐので、animation-fill-modeはforwardsかbothにしてください。
変更するプロパティは、前のアニメーションの最後と次のアニメーションの最初の数値を合わせます(未指定の場合は初期値)。

```:css
animation: 
  anime1 1s ease 0s 1 alternate forwards running,
  anime2 1s ease 1s 1 alternate forwards running,
  anime3 1s ease 2s 1 alternate forwards running;

```

#### animation-timing-functionの値

|値|内容|cubic-bezierで表現すると|
|---|---|---|
|ease|開始と完了を滑らかにする(初期値)|cubic-bezier(0.25, 0.1, 0.25, 1.0)|
|linear|一定速度|cubic-bezier(0.0, 0.0, 1.0, 1.0) |
|ease-in|ゆっくり始まる|cubic-bezier(0.42, 0, 1.0, 1.0)|
|ease-out|ゆっくり終わる|cubic-bezier(0, 0, 0.58, 1.0) |
|ease-in-out|ゆっくり始まってゆっくり終わる|cubic-bezier(0.42, 0, 0.58, 1.0) |
|cubic-bezier|指定による|-|


#### cubic-bezierの指定方法
```:css
/* cubic-bezier(x1, y1, x2, y2); */
cubic-bezier(0.42, 0, 0.58, 1.0);
```
Chrome DevToolsのcubic-bezierの前のアイコンをクリックすると、設定したイージングの動きを見ながら調整できて便利です。


#### animation-timing-functionの値(コマ送り)

|値|内容|steps(n,start/end)で表現すると|
|---|---|---|
|step-start|アニメーション開始直後に完了状態になりそのままキープ|steps(1, start)|
|step-end|アニメーションが完了するまで初期状態で、完了時にいきなり完了状態になる|steps(1, end)|
|steps(n, start)|step-startをn(任意の数)で分割してコマ送りアニメーション|-|
|steps(n, end)|step-endをn(任意の数)で分割してコマ送りアニメーション|-|

steps()の指定方法

```:css
animation-timing-function: steps(10,start);
```



### CSS Animationのイベントを取得する

|Transitionのイベント|発生タイミング|
|---|---|
|animationend|CSSAnimationend完了時|
|animationiteration|CSS Animationendの繰り返し時|
|animationstart|CSS Animationend開始時|


```:js
moveTarget.addEventListener('animationend', () => {
    console.log('Animationが完了しました。');
});

moveTarget.addEventListener('animationiteration', () => {
    console.log('Animationが繰り返されました。');
});

moveTarget.addEventListener('animationstart', () => {
    console.log('Animationが開始しました。');
});
```


## ツール

### アニメーションライブラリ
[Animate.css](https://daneden.github.io/animate.css/)
[anime.js](https://animejs.com/)


### アニメーションコードジェネレータ
[Animista](http://animista.net/)