🫥

VueのTransitionタグを理解する

2024/09/28に公開

Vueには、CSSのtransitionプロパティを制御する<Transition>タグがあります。この<Transition>タグの使い方と、代替となるTailwindを使った書き方を見ていきます。

CSSのtransitionプロパティとは

要素のフェードイン/アウト、スライドイン/アウトなど、単純なアニメーションの記述に使用できるプロパティ。CSSのあるパラメータが動的に変化するとき(要素の表示/非表示切り替えや、hover時の背景色の変化など)に、その変化を補完するアニメーションを記述するものです。

opacityが動的に変化する例(トランジションなし):

クリックで表示/非表示が切り替わる要素の例です。
ここでは、ボタンがクリックされるたびに、opacity: 0;を指定したhiddenクラスをつけたり外したりすることで、表示/非表示を切り替えています。

opacityが動的に変化する例(トランジションあり):

このboxクラスにtransitionプロパティを指定すると、変化を補完するアニメーションが描画されます。つまり、opacityが0から1になったり、1から0になったりする変化をアニメーションで繋いでくれます。

なお、transitionと似たプロパティにanimationがあります。
transitionプロパティで記述できるのは一方向のシンプルなアニメーションですが、animationプロパティでは複雑な変化や繰り返しの指定が可能になります。

<Transition>タグとは

さきほどの例ではopacityを使った表示/非表示制御をしましたが、Vueではこのような制御を動的に行う場合v-ifv-showを使うことが一般的です。

v-showを使った表示制御の例:

このv-if/v-showを使う場合、先程のようなクラスの付け替えではトランジション効果を追加することができません。

v-ifの場合は非表示時に要素自体がDOMから削除され、またv-showの場合は非表示時にdisplay: none;が適用されるため、表示↔非表示の切り替えの際のプロパティの変化が離散的になります。
transitionプロパティはopacitytransformのような、連続的な値を持つプロパティの変化を補完するものなので、これらの制御といっしょに使うことはできません。

この、v-if, v-showを使った制御にトランジション処理を付与したい場合に使用するのが<Transition>タグです。

<Transition>タグを使用して、v-showを使っている要素にトランジション処理を追加した例:

<Transition>タグにname="fade"を指定して、fade-*クラスにトランジション方法を記述することで、トランジション効果を追加しています。<Transition>タグの詳しい使い方はドキュメントを参照ください。
トランジション | Vue.js

Tailwindクラスを使った代替手段

この<Transition>タグを使用したアニメーションを実装してfindの社内レビューに出したところ、あえてv-showを使わずにTailwindクラスの付け替えでopacity等のプロパティを制御する方法を提案されました。

Tailwindクラスの付け替えでトランジション効果を記述する例:

<Transition>タグとv-showを使用した場合の、トランジションに関連する記述は以下です。

<template>
  <Transition name="fade">
    <div class="box" v-show="show">hello</div>
  </Transition>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

一方、Transitionを使わずに、tailwindのクラスの制御で対応している例は以下です。

<template>
  <div
    class="box transition-opacity duration-500"
    :class="{ 'opacity-0 pointer-events-none ': !show }"
  >
    hello
  </div>
</template>

メリットとしては以下があります。

  • コード量が少なく済む
  • CSSの記述がtemplate部分のみで完結するので、何をしているか読み解きやすい
    • <style>部分まで移動しなくてよくなる。行数の多いVueファイルになると、該当するスタイルを見に行って戻ってきて、は面倒だったりしますよね。
  • トランジションしたい要素の外側をTransitionタグで囲わなければいけないのは直感的に違和感がある。(ある要素の効果はその要素自体に記述したい気持ち)

一方で以下のようなデメリットもあると思っています。

  • v-showを使っていないのに動的に表示が制御されるのは直感的でない
  • アニメーションを付けたい箇所には逐一transition-opacity duration-500のようなおまじない書く必要があり、冗長かつ記述量も多くなる[1]

複数箇所で同じトランジション効果を使っている場合は、<Transition>タグを使ったうえで、共通で読み込まれるCSSにスタイルを定義するほうがシンプルに書けそうです。例えばname="fade"とする場合のfade-*クラスの共通のCSSファイルに記述するとか。
今回のTailwindで直接指定する方法は、そういった共通化するまでもないような、トランジションの少ないプロジェクトでは選択肢となりそうです。

参考にしたページ

脚注
  1. 単に記述量を減らすなら、Tailwindの@applyを使ってクラスをまとめる手もありそうです。 ↩︎

株式会社find | 落とし物クラウド

Discussion