VueでイケてるTransition! fade, slide編

## 前提
この記事は極力**VueのAPI**と**CSS**だけで**Transitionアニメーション**を実装するという趣旨の元執筆しています。
また`transitionプロパティ`と**Vue**ある程度知っていると仮定した上で話を進めていきます。
よく知らないという方は[こちら](https://developer.mozilla.org/ja/docs/Web/CSS/transition)を閲覧してから、この記事を閲覧することをオススメします。
## 注意
この記事はデモに**CodePen**を使用していますが、**transition**に必要なCSSを判別しやすくするため、**transition**関連のスタイルは**CSS**の欄に、それ以外のスタイルは**HTML**の`<style>`タグに書いています。
あまり褒められたやり方ではないので、本番環境では真似しないでください

## まず初めに
**Vue**では`v-if`か`v-show`に真偽値を入れてやることで、要素の表示と非表示を切り替えることができます。
しかし、その要素に**CSS**で`transitionプロパティ`を設定してやっても、上手く実行されません。
**Vue**には`<transition>`というラッパーコンポーネントが用意されていて、これで**transition**させたい要素を囲むことで上手く**transition**が実行されます。

詳しくはこちらを参照してください => [Enter/Leave とトランジション一覧](https://jp.vuejs.org/v2/guide/transitions.html)

```html:transition.vue
<template>
  <transition name="fade">
    <div v-if="show">
      Fade
    </div>
  </transition>
</template>
```
`<transition>`コンポーネントで囲むことで**CSSクラス**が付与されます。

```CSS:transition.vue
<style scoped>
.fade-enter-active, .fade-leave-active {
  /* 表示されている際のCSSはこのブロックに記述 */
}
.fade-enter, .fade-leave-to {
  /* 非表示の際のCSSはこのブロックに記述 */
}
</style>
```
付与されるクラス名は`<transition>`の`name`で指定した値によって変わります。
具体的には上記のクラス名の`fade`の部分がそれに当たります。
例えば`name`に指定した値が`slide`だった場合は

```CSS:transition.vue
<style scoped>
.slide-enter-active, .slide-leave-active {
  /* 表示されている際のCSSはこのブロックに記述 */
}
.slide-enter, .slide-leave-to {
  /* 非表示の際のCSSはこのブロックに記述 */
}
</style>
```
の様になります。

ちなみにラッパーコンポーネントは、最終的な`DOM`には表示されないので、階層に気を付けなくても大丈夫です！
## Fade
**Fade**は**Transitionアニメーション**の中でも非常にシンプルでポピュラーな物です。

```css:fade.css
.fade-enter-active, .fade-leave-active {
  will-change: opacity;
  transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
}
.fade-enter, .fade-leave-to {
  opacity: 0
}
```
**Fade**の実装に必要なスタイルは上記の様になります。

### will-changeについて
**Fade**を実装する上で、このプロパティは必要ありません。
ではなぜこのプロパティが記述されているのか？
`will-change`はブラウザにどの要素の変更がよそされるのかを通知し、ブラウザはその通知を元に最適化を行います。
これにより応答パフォーマンスが向上します。

#### will-changeの使用に関する注意
今回は紹介の為に使用しましたが、`will-change`はいいことばかりではありません。
近年のブラウザは何も指定せずともできる限り、最適化を行っており、`will-change`をいたずら複数指定することは、必要以上のマシンリソースを消費してしまいます。

あくまで、ページの表示が遅いサイトの応答パフォーマンスを向上させるための**最終手段**として使用することをオススメします。

詳しくは[こちら](https://developer.mozilla.org/ja/docs/Web/CSS/will-change)をご覧ください

## Top Slide
これから紹介する**slide系Transition**はWebページにちょっとした遊び心を加えます。
ただし、使いすぎると**ユーザー**に鬱陶しさを与えます。
使いどころとしては**トースト通知**などがあるでしょう。

```css:TopSlide.css
.top-enter-active, .top-leave-active {
  transform: translate(0px, 0px); 
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.top-enter, .top-leave-to {
  transform: translateY(-100vh) translateY(0px);
}
```
### transform
**slide系transition**では`transform`プロパティが重要になってきます。
`transform`プロパティはその名前の通り要素の**回転、拡大縮小、傾斜、移動**を行うことができます。

詳しくは[CSS3クイックリファレンス](http://www.htmq.com/css3/transform.shtml)と[MDN web docs](https://developer.mozilla.org/ja/docs/Web/CSS/transform)をご覧ください

### `vh`とは？
上記の`CSS`をコピペで使用する場合は注意が必要です。

```css
.top-enter, .top-leave-to {
  transform: translateY(-100vh) translateY(0px);
}
```
で`-100vh`と指定していますが、この`vh`を見慣れないビギナーの方もいると思います。
この`vh`とは`viewport height`の略称で、要は表示されている範囲をさしています。
上記の例で言えば`100vh`は**view portの高さ**と同じ高さの数値を得る。所謂パーセンテージなのです。
これを正常に動作させる為には`html`の`<head>`要素の中に以下の`<meta>`要素を記述する必要があります。

```html:index.html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```
最近の高性能なエディタを使っていれば`html`ファイルを作ったらすでに書いてあったという人もいると思います。

**viewportを元に計算する単位は全部で4つ存在します。**

|単位|略称元|効果|
|:--|:--|:--|
|vh|viewport height|ビューポートの高さに対する割合|
|vw|viewport width|ビューポートの幅に対する割合|
|vmin|viewport minimum|ビューポートの幅と高さのうち、値が小さい方に対する割合|
|vmax|viewport max|ビューポートの幅と高さのうち、値が大きい方に対する割合|

#### `%`と何が違うの？
誰もが一度は使う`%`は親の値に依存しています。
例えば親が`height: 400px`だとすれば、`%`は親の`height`を元に計算されてしまいます。
そこで、どの階層にいても親要素に関係なく、Webページの表示領域の`height`と`width`を元に計算したいと行った場合に`vh`や`vw`を使うと期待通りの効果が得られるでしょう。

## Top Left Slide
```css:TopLeftSlide.css
.top-left-enter-active, .top-left-leave-active {
  transform: translate(0px, 0px); 
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.top-left-enter, .top-left-leave-to {
  transform: translateY(-100vh) translateX(-100vh);
}
```

## Top Right Slide
```css:TopRightSlide.css
.top-right-enter-active, .top-right-leave-active {
  transform: translate(0px, 0px); 
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.top-right-enter, .top-right-leave-to {
  transform: translateY(-100vh) translateX(100vh);
}
```

## Bottom Slide
```css:BottomSlide.css
.bottom-enter-active, .bottom-leave-active {
  transform: translate(0px, 0px);
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.bottom-enter, .bottom-leave-to {
  transform: translateY(100vh) translateY(0px);
}
```

## Bottom Left Slide
```css:BottomLeftSlide.css
.bottom-left-enter-active, .bottom-left-leave-active {
  transform: translate(0px, 0px);
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.bottom-left-enter, .bottom-left-leave-to {
  transform: translateY(100vh) translateX(-100vh);
}
```

## Bottom Right Slide
```css:BottomRightSlide.css
.bottom-right-enter-active, .bottom-right-leave-active {
  transform: translate(0px, 0px);
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.bottom-right-enter, .bottom-right-leave-to {
  transform: translateY(100vh) translateX(100vh);
}
```

## Left Slide
```css:LeftSlide.css
.left-enter-active, .left-leave-active {
  transform: translate(0px, 0px);
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.left-enter, .left-leave-to {
  transform: translateX(-100vw) translateX(0px);
}
```

## Right Slide
```css:RightSlide.css
.right-enter-active, .right-leave-active {
  transform: translate(0px, 0px);
  transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.right-enter, .right-leave-to {
  transform: translateX(100vw) translateX(0px);
}
```

## demo(CodePen)
<p data-height="600" data-theme-id="0" data-slug-hash="WYzeve" data-default-tab="html,result" data-user="nexus0831" data-pen-title="CSS Transition" class="codepen">See the Pen <a href="https://codepen.io/nexus0831/pen/WYzeve/">CSS Transition</a> by マテリアルお兄さん (<a href="https://codepen.io/nexus0831">@nexus0831</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

## 最後に
いかがだったでしょうか？
基本となる`Fade`と全部で8方向からの`Slide`を今回は実装してみました。
**ダイアログ**や**アラート**、**通知**を出す際にこれらが使えると、少しばかりユーザーに楽しさを与えることができるでしょう。
少なくとも私は何度も押してしまう位には好きです（笑）