【CSSアニメーション】transitionのイージングにease-inやease-outを適当に設定するのはやめましょう

# はじめに
この記事は普段transition-timing-functionの値に
なんとなく`ease`、`ease-in`、`ease-out`、`ease-in-out`を設定している方に読んでいただきたい内容になります。

アニメーションが苦手という方も、
この記事で紹介する6つのポイントを抑えることで
普段気づいていたけど対処法がわからなかった**アニメーションの違和感**の解消方法を学んでいただければ幸いです。

## イージングの種類や性質
まずは**CSSで使える代表的なイージングの種類**と、**イージングの強弱**について説明します。

### CSSで使える代表的なイージングの種類
代表的なイージングは全部で25パターンあります。
とても多い印象を受けたかと思いますが、
**イージングとしては、実は8種類**だけです。
また、本記事は下記のイージングを元に説明していきます。
何となく、「これだけあるのかー。」くらいで見てください。
※cubic-bezier（キュービックベジェ）の値などはひとまず覚える必要はありません。

```scss:easing.scss
$linear:         cubic-bezier(0.250, 0.250, 0.750, 0.750);

$easeInSine:     cubic-bezier(0.47,  0,     0.745, 0.715);
$easeOutSine:    cubic-bezier(0.39,  0.575, 0.565, 1    );
$easeInOutSine:  cubic-bezier(0.445, 0.05,  0.55,  0.95 );
$easeInQuad:     cubic-bezier(0.55,  0.085, 0.68,  0.53 );
$easeOutQuad:    cubic-bezier(0.25,  0.46,  0.45,  0.94 );
$easeInOutQuad:  cubic-bezier(0.455, 0.03,  0.515, 0.955);

$easeInCubic:    cubic-bezier(0.55,  0.055, 0.675, 0.19 );
$easeOutCubic:   cubic-bezier(0.215, 0.61,  0.355, 1    );
$easeInOutCubic: cubic-bezier(0.645, 0.045, 0.355, 1    );
$easeInQuart:    cubic-bezier(0.895, 0.03,  0.685, 0.22 );
$easeOutQuart:   cubic-bezier(0.165, 0.84,  0.44,  1    );
$easeInOutQuart: cubic-bezier(0.77,  0,     0.175, 1    );

$easeInQuint:    cubic-bezier(0.755, 0.05,  0.855, 0.06 );
$easeOutQuint:   cubic-bezier(0.23,  1,     0.32,  1    );
$easeInOutQuint: cubic-bezier(0.86,  0,     0.07,  1    );
$easeInExpo:     cubic-bezier(0.95,  0.05,  0.795, 0.035);
$easeOutExpo:    cubic-bezier(0.19,  1,     0.22,  1    );
$easeInOutExpo:  cubic-bezier(1,     0,     0,     1    );

$easeInCirc:     cubic-bezier(0.6,   0.04,  0.98,  0.335);
$easeOutCirc:    cubic-bezier(0.075, 0.82,  0.165, 1    );
$easeInOutCirc:  cubic-bezier(0.785, 0.135, 0.15,  0.86 );
$easeInBack:     cubic-bezier(0.6,  -0.28,  0.735, 0.045);
$easeOutBack:    cubic-bezier(0.175, 0.885, 0.32,  1.275);
$easeInOutBack:  cubic-bezier(0.68, -0.55,  0.265, 1.55 );
```

CSSの場合は、
`transition: opacity 0.3s cubic-bezier(0.39, 0.575, 0.565, 1);`
のように記述しますが、本記事はSCSSで記述することを前提で説明します。

上記のような変数をSCSSで記述すると
`transition: opacity 0.3s $easeOutSine;`
となります。

イージングの値も何が設定されているかわかりやすいですね。

### イージングの強弱
イージングには`Sine`、`Quad`、`Cubic`、`Quart`、`Quint`、`Expo`、`Circ`、`Back`の8種類あり、
下記のように**Sineが一番緩やかな変化となり、Expoにいくにつれてだんだん急激な変化**となります。
この順番はとても重要です。しっかり覚えておきましょう。

```
Sine（もっとも緩やかな変化）
Quad
Cubic
Quart
Quint
Expo（もっとも急激な変化）
```

また、下記は特別なイージングです。

```
Circ（Expoよりもイージングの余韻が長い）
Back（一度バウンドするようなイージング）
```

個人的には簡易なバウンドはBackを使用しますが、
こだわりのあるバウンドを出したい場合は、CSS animationを利用します。
オノマトペでいうと「ト〜ン、トン、トトン」と言ったアニメーションなどです。
（CSS animationに関しては後日記事をUPDATEする予定です。）

イージングに関しては下記の参考サイトをご確認ください。
[イージング関数チートシート](https://easings.net/ja)

では本題に入っていきます。

## 心地良いアニメーションに近づくための6つのポイント
この6つのポイントはとても大切です。
これを意識することで、違和感のない心地良いサイトのベースが作れます。

- [opacity、colorには余計なイージングをつけない](#opacitycolorには余計なイージングをつけない)
- [マウスオーバーでアニメーションを待たせない](#マウスオーバーでアニメーションを待たせない)
- [マウスアウトも意識する](#マウスアウトも意識する)
- [transition allは使わない](#transition-allは使わない)
- [急激な変化のあるeaseInOutXxxxは使わない](#急激な変化のあるeaseinoutxxxxは使わない)
- [しっくりこない時はイージングを自作する](#しっくりこない時はイージングを自作する)

## opacity、colorには余計なイージングをつけない
**ポイント：opacityやcolorには `$linear` か `$easeOutSine` をつけましょう。**

心地悪さを感じやすい一つが、opacityやcolorに余計なイージングがかかっている場合です。
早速BadとGoodを紹介します。

<p class="codepen" data-height="500" data-theme-id="22321" data-default-tab="result" data-user="mokichi" data-slug-hash="QWKxLYe" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="opacity_color">
  <span>See the Pen <a href="https://codepen.io/mokichi/pen/QWKxLYe">
  opacity_color</a> by seiya kato (<a href="https://codepen.io/mokichi">@mokichi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

A、B、Cのボタンのうち、どのボタンが心地悪いと感じましたか？

正解は「B」です。
心地悪いボタン「B」には `$easeInOutQuart` が設定されています。
ボタン「A」には `$easeOutSine` 、
ボタン「C」には `$linear` が設定されており、
それぞれdurationは `0.3s` が設定されています。

ボタン「C」はイージングが無い`$linear`が設定されているため、体感はボタン「A」に比べてゆっくりに感じます。

このように`opacity`、`color`、`background-color`などは、変化させるイージングを `$linear` か `$easeOutSine` にすることで自然に変化させることができます。


## マウスオーバーでアニメーションを待たせない

**ポイント：マウスオーバーのdurationは `0.25s〜0.45s`**

例えば、ボタンの色を反転させるようなアニメーションの場合、マウスオーバーしてからアニメーション完了までにかかる時間が長いと、ユーザーにとって**アニメーションが終わるまで待たせている状態**になります。

<p class="codepen" data-height="350" data-theme-id="22321" data-default-tab="result" data-user="mokichi" data-slug-hash="MWjzvvy" style="height: 350px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="duration_delay">
  <span>See the Pen <a href="https://codepen.io/mokichi/pen/MWjzvvy">
  duration_delay</a> by seiya kato (<a href="https://codepen.io/mokichi">@mokichi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

この、**待たされるという感覚**に気づく事は非常に大切です。

秒数に幅を持たせている理由としては `$linear` か `$easeOutSine` で体感速度が異なるためです。
**気持ち遅い・早い**と感じた場合はdurationを `0.05s` ずつ増減してみると良いです。

ただ、すべてがこのdurationに収めないといけない。というわけではありません。
ここで意識することは、触れてみて**ユーザーが待たされている感覚があるかどうか**という事です。

<p class="codepen" data-height="520" data-theme-id="22321" data-default-tab="result" data-user="mokichi" data-slug-hash="mdrKdOv" style="height: 520px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="delay_duration">
  <span>See the Pen <a href="https://codepen.io/mokichi/pen/mdrKdOv">
  delay_duration</a> by seiya kato (<a href="https://codepen.io/mokichi">@mokichi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

リンクAとリンクBの違いがわかりますか？
まずは各リンクに設定した値を見てみましょう。

**リンクAのtransitionの設定**
- テキストは`opacity $linear 0.3s`
- 連動するサムネイルのscaleアニメーションは`transform $easeOutCubic 1.8s`

**リンクBのtransitionの設定**
- テキストとサムネイルのduration、easingはそれぞれ同じ値の`$easeOutCubic 1.8s`

AB共にサムネイルだけの値で見ると**待たされている**に当てはまります。

ただ、Aのマウスオーバーは、ユーザーとしては**表示される文字に対しては待たされた感覚が無い**ため、
サムネイルの拡大アニメーションが続いていたとしても、不快には思わないのです。
一方リンクBの文字はゆったりと表示されていることがわかります。

もう一度マウスオーバーした時の文字のアニメーションを注視してみてください。
違いがわかるはずです。


## マウスアウトも意識する

**ポイント：マウスアウトのアニメーションも待たせないよう、別々のdurationを指定する**

前述した**マウスオーバーでアニメーションを待たせない**では、あくまでマウスオーバーのみにフォーカスしました。
左右のバナーを行き来すると、フォーカスアウトした画像がぬるっと動いていて気になります。

**マウスアウト = フォーカスから外れる事**です。
フォーカスから外れた要素は、**目についてしまうアニメーション**を避けるべきです。

<p class="codepen" data-height="520" data-theme-id="22321" data-default-tab="result" data-user="mokichi" data-slug-hash="wvzxJGM" style="height: 520px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="focus_duration">
  <span>See the Pen <a href="https://codepen.io/mokichi/pen/wvzxJGM">
  focus_duration</a> by seiya kato (<a href="https://codepen.io/mokichi">@mokichi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

ここでのポイントは、フォーカスアウトした要素は気にならない速度で元に戻すことです。
今回は`transition: transform 0.6s $easeOutCubic;`という設定で、余韻を多少持たせながらサムネイルを元のサイズに戻しています。

[マウスオーバーでアニメーションを待たせない](#マウスオーバーでアニメーションを待たせない)で紹介した、画像をマウスオーバーする例をもう一度見てみましょう。
マウスアウトした後の画像に少しだけ意識を向けてみてください。
**画像が元のサイズに戻る時にもたつき（遅さ）**を感じると思います。

## transition allは使わない
**ポイント：opacityやcolor系とtransform系はイージングを分ける**

とてもよくあるパターンかと思います。
`all`は一括で設定することができてとても便利ですが、
opacityとtransformを同時に指定すると、違和感のあるアニメーションになりがちです。
今までまとめて記述している方は下記のように指定するようにしましょう。
カンマで区切って別々の指定をします。

```
transition: all 0.8s $easeOutQuint;
↓
transition: color 0.3s $easeOutSine, transform 0.8s $easeOutQuint;
```

下記のようにopacityやcolor系などの**同じイージングを指定しても違和感のないもの**はallを指定しても問題はありません。

```scss:
a {
  color: blue;
  background-color: blue;
  transition: all 0.3s $easeOutSine;
  &:hover {
    color: white;
    background-color: red;
  }
}
```

## 急激な変化のあるeaseInOutXxxxは使わない
**ポイント：transform系はeaseOutXxxxをベースにする**

easeInOutXxxxは波を打つようなイージングになりがちです。
スクロール時に下からコンテンツがせり上がるようなアニメーションには`easeOutXxxx`が自然なアニメーションになります。

<p class="codepen" data-height="520" data-theme-id="22321" data-default-tab="result" data-user="mokichi" data-slug-hash="KKgBWrZ" style="height: 520px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="easeOutXxxxx">
  <span>See the Pen <a href="https://codepen.io/mokichi/pen/KKgBWrZ">
  easeOutXxxxx</a> by seiya kato (<a href="https://codepen.io/mokichi">@mokichi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

ブレーキをかけたようなアニメーションにしたい場合は`easeInXxxx`にすると「キュッ」と止まる印象になるため、案件によって使い分けます。


## しっくりこない時はイージングを自作する
**ポイント：InとOutのベジェ曲線をそれぞれ変える**

8種類の代表的なイージングを試してみてどれもしっくりこない場合は、
cubic-bezier（キュービックベジェ）の値をカスタマイズし、
独自のイージングを設定します。

ただ闇雲に値を調整するのは流石に大変なので、
今回は[cubic-bezier.com](https://cubic-bezier.com/)というジェネレータを利用してオリジナルなイージングを作成します。

今回は下記をイメージして作成しました。

**イージングのイメージ**

- easeIn: 少しだけイージングをかける
- easeOut: かなり余韻をもたせたい
- 全体的にふわっとした感じ

下記URLにアクセスし、durationに**1.6**を設定し、**[GO!]**をクリック。

https://cubic-bezier.com/#.33,.01,.06,.99


## まとめ
簡単ではありますがアニメーションのポイントを紹介しました。
説明した6つのポイントを意識することで、少なくとも違和感の無いアニメーションを実装することができます。

まだまだ伝えたいことはたくさんあるので、この記事は少しづつアップデートしていきたいと思います。

一緒に感覚を備えていきましょう。