（初心者向け）CSSホバーアニメーションの実装方法

## この記事で得られるもの
- CSSのホバーのアニメーションの実装の**考え方**がわかる
- CSSでホバーのアニメーションの実装方法を**順を追って**理解できる
- 考え方が理解できるため、サンプルコードのコピペではなく**応用したコード**が書ける

## 想定読者
- CSSのセレクタ、プロパティの基本は知っているが、ホバーアニメーションを書こうと思うと**混乱する**方
- 動くものは書けるが、正しい**綺麗な書き方**を知りたい方
- コードレビューでプロパティの重複や不要なプロパティを**指摘される**ことがある方

## 前提
**transition**を前提としています。
animation、JavaSctiptを使った動きはここでは解説しません。

## 実装
### 動きを定義するのではなく、ホバー状態・通常状態を定義し、その間を変化する
これが全ての考え方の基本になります。
どう動くか考えるのではなく、それぞれの状態ごとに装飾が定義され、その間を徐々に変化すると覚えてください。
基本がわかれば、大抵のデザインはこの応用で実装できます。

### ホバーするとリンクの下線が伸びながら出現する場合

```html
<a class="block">リンク<span class="block__decoration"></span></a>
```

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


#### 1.先にホバー状態をコーディング
色々な考え方はあると思いますが、私は通常状態のセレクタ内に一旦**ホバー状態をコーディング**することをおすすめします。
なぜかと言うと、通常状態は装飾が非表示だったりシンプルで、ホバー状態で装飾が出現することが多いためです。
通常状態を先にコーディングしようとしても「ホバーするとこう出現するから...」ということを結局考えることが必要で、**出現していない状態を先に考える**ことは慣れていないと**難しい**です。

```css
.block {
  position: relative;
}

/* まだ:hoverステートはつけない */
/* ホバー時に現れる下線を一旦コーディングしてしまう */
.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
}
```

これで画面にはホバー状態の装飾が表示されるようになります。

#### 2.次に通常状態をコーディング
##### 2.1.ホバー状態と通常状態で値が変わるプロパティを探す
例えば、文字色が変わるのであれば`color`、背景色が変わるのであれば`background(background-color)`ですね。
特に注意が必要なのは**なかったものが現れる**場合で、この場合は透明だから見えてないのか、サイズが小さい（0）から見えてないのか、画面外にあるから見えてないのか、など**どう捉えるか**を決めましょう。
透明だから見えていないなら不透明度を上げながら出現するし、サイズが小さいから見えていないなら大きくなりながら出現します。
また、変化するものが以下である場合、基本的に表のプロパティを使うようにしましょう。理由は簡単に言うと、それ用にあるプロパティのため記述も直接的だし動きもスムーズだからです。

| 動き | NGプロパティ | OKプロパティ |
| ---- | ---- | ---- |
| その場で出現する | ~~display~~ | opacity |
| 伸びて出現する | ~~height, width~~ | transform: scale |
| 移動する | ~~top, left, right, bottom~~ | transform: translate |

今回は横幅が**伸びて出現**するようにしたいので、`transform: scale`を使います。

##### 2.2.通常状態に書き換える
先の手順でホバー状態と通常状態で値が変わるプロパティは`transform: scale`であることがわかりました。
このプロパティを通常状態・ホバー状態それぞれに記載します。
今回は非表示（幅0倍）から表示（幅1倍）に変更したいため、以下の通り記載します。

```css
.block {
  position: relative;
}

.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
  /* 通常状態は幅を0にして非表示 */
  transform: scaleX(0);
}

.block:hover .block__decoration {
  /* ホバー状態はそのまま表示 */
  transform: scaleX(1);
}
```

これで画面はホバーすると装飾が切り替わるようになります。

#### 3.変化を定義する
あとはアニメーションのタイミングと速さを決めるだけです。

```css
.block {
  position: relative;
}

.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
  transform: scaleX(0);
  /* 速さを指定 */
  transition: .5s;
}

.block:hover .block__decoration {
  transform: scaleX(1);
}
```

これで画面はサンプルコードと同じ状態になります。

### ホバーするとリンクの下線が下からふわっと出現する場合
他の動きや形でも考え方は同じです。

```html
<a class="block">リンク<span class="block__decoration"></span></a>
```

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

#### 1.先にホバー状態をコーディング

```css
.block {
  position: relative;
}

.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
}
```

#### 2.次に通常状態をコーディング

```css
.block {
  position: relative;
}

.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
  /* 通常状態は文字より下に離し透明にしておく */
  transform: translateY(5px);
  opacity: 0;
}

.block:hover .block__decoration {
  /* ホバー状態は文字は文字に近づけて不透明にする */
  transform: translateY(0);
  opacity: 1;
}
```

#### 3.変化を定義する

```css
.block {
  position: relative;
}

.block__decoration {
  position: absolute;
  left: 0;
  bottom: -3px;
  display: block;
  width: 100%;
  height: 2px;
  background: #00f;
  transform: translateY(5px);
  opacity: 0;
  /* 速さを指定 */
  transition: .5s;
}

.block:hover .block__decoration {
  transform: translateY(0);
  opacity: 1;
}
```

## 補足
1. 正しさよりも分かりやすさを優先している箇所があります
1. NGプロパティは絶対使うなというわけではなく、回避するデメリットが大きければ使っても間違いではありません
1. あくまで思考を整理するための手順ですので、慣れればこの手順でやる必要は全くありません