Vue 3 のトランジションとアニメーション:Transition、TransitionGroup、6つのCSSクラス、およびJSフック
トランジションやアニメーションは、Vue アプリをよりダイナミックなものにします。要素がビューポートに出入りする際の滑らかなトランジションや、リストが変更された際の洗練された再描画などが挙げられます。Vue には <Transition> および <TransitionGroup> コンポーネントが含まれており、これらは CSS クラス名や JavaScript フックと連携して、さまざまなアニメーション効果を実現します。
遷移アニメーションをマスターすることは、ユーザー体験の向上の鍵となります。優れたアニメーションは、アプリに「スムーズで、反応が良く、プロフェッショナルな」印象を与えます。
1. 学習内容
<Transition>単一要素の入退場アニメーション- 6つのCSSクラスフック(v-enter-from / v-enter-active など)
<TransitionGroup>リストのアニメーション- JavaScriptフック(@before-enter / @enter など)
- サードパーティ製のアニメーションライブラリ(@vueuse/motion、GSAP)の統合
- Animate.css の統合
- 5つの主要な実例
2. 「タブ切り替え」ハードスイッチの扱いにくさ
(1) 課題:コンポーネントが突然消えたり現れたりすること、UIがちらつくこと
アリスの管理画面にはタブ切り替え機能がありました:
VUE
<!-- ❌ The "Flip" Version:v-if Sudden Switch -->
<template>
<button @click="currentTab = 'home'">Home</button>
<button @click="currentTab = 'profile'">Profile</button>
<div v-if="currentTab === 'home'">Home Content</div>
<div v-else-if="currentTab === 'profile'">Profile Content</div>
</template>
ユーザー体験:
- タブを切り替えたときに突然表示されたり消えたりする
- 遷移アニメーションがないため、「違和感」を感じます。
- プロ意識の欠如
(2) Vueのトランジション実装:タグ1つ、クラス6つ
VUE
<!-- ✅ Correct Version:Smooth Transition -->
<template>
<button @click="currentTab = 'home'">Home</button>
<button @click="currentTab = 'profile'">Profile</button>
<Transition name="fade" mode="out-in">
<div v-if="currentTab === 'home'" key="home">Home Content</div>
<div v-else-if="currentTab === 'profile'" key="profile">Profile Content</div>
</Transition>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
ユーザー体験:
- タブを切り替える際のスムーズなフェードイン・フェードアウト
- 0.3秒のトランジションで、プロフェッショナルな仕上がりになります
- 6つのCSSクラスが自動的に適用されます
(3) 収益
トランジションを追加した後:
- ユーザー体験:「もっさり」から「スムーズ」へ
- プロ意識:大幅に改善された
- コード量:1つの
<Transition>タグ + 6つのCSSクラス - カスタマイズ可能:4つのトランジション名+3つのモード
3. 遷移:単一要素
(1) 基本的な使い方
VUE
<template>
<button @click="show = !show">Toggle</button>
<Transition name="fade">
<p v-if="show">Hello Vue</p>
</Transition>
</template>
<style>
/* 6 CSS classes, Vue Auto-add/Remove */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
(2) 6つのCSSクラスの詳細な解説
| クラス | トリガー条件 | 目的 |
|---|---|---|
v-enter-from |
要素挿入前 | 初期状態 |
v-enter-active |
要素挿入の全プロセス | 遷移プロセス |
v-enter-to |
要素を挿入した後 | 最終状態 |
v-leave-from |
要素が離れる前に | 初期状態 |
v-leave-active |
要素がプロセス全体から離れる | 遷移プロセス |
v-leave-to |
要素が離れた後 | 終了状態 |
(3) 命名規則
VUE
<!-- v-bind:name="fade" → 6 classes are .fade-xxx -->
<Transition name="fade">...</Transition>
<!-- Don't write name → Default v-xxx (6 classes are .v-xxx) -->
<Transition>...</Transition>
<!-- News name -->
<Transition :name="transitionName">...</Transition>
(4) 3つのモード
VUE
<!-- 1. Default Mode:Entry and exit occur simultaneously(Overlap) -->
<Transition name="fade">
<div v-if="show">Content</div>
</Transition>
<!-- 2. out-in:Leave first, then enter(Recommendations,Avoid Overlapping) -->
<Transition name="fade" mode="out-in">
<div v-if="show">Content</div>
</Transition>
<!-- 3. in-out:Enter first, then leave(Rare) -->
<Transition name="fade" mode="in-out">
<div v-if="show">Content</div>
</Transition>
4. CSSアニメーションの5つの種類
(1) フェードインとフェードアウト(最も一般的)
CSS
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
(2) スライド
CSS
.slide-enter-active, .slide-leave-active {
transition: transform 0.3s;
}
.slide-enter-from {
transform: translateX(-100%);
}
.slide-leave-to {
transform: translateX(100%);
}
(3) ズーム
CSS
.scale-enter-active, .scale-leave-active {
transition: transform 0.3s;
}
.scale-enter-from, .scale-leave-to {
transform: scale(0);
}
(4) 回転
CSS
.rotate-enter-active {
transition: transform 1s;
}
.rotate-enter-from {
transform: rotate(0deg);
}
.rotate-leave-active {
animation: bounce 0.5s;
}
@keyframes bounce {
0% { transform: scale(0); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
(5) 複合アニメーション
CSS
.combo-enter-active, .combo-leave-active {
transition: all 0.3s;
}
.combo-enter-from {
opacity: 0;
transform: translateX(-50px) scale(0.8);
}
.combo-leave-to {
opacity: 0;
transform: translateX(50px) scale(0.8);
}
5. TransitionGroupのリストアニメーション
(1) 基本的な使い方
VUE
<template>
<button @click="add">Add</button>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.name }}
<button @click="remove(item.id)">×</button>
</li>
</TransitionGroup>
</template>
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' }
])
function add() {
const id = Date.now()
items.value.push({ id, name: `Item ${id}` })
}
function remove(id) {
items.value = items.value.filter(i => i.id !== id)
}
</script>
<style>
/* 6 classes, However, for list items, enter/leave/move */
.list-enter-active, .list-leave-active {
transition: all 0.5s;
}
.list-enter-from, .list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-leave-active {
position: absolute; /* Remove from the document flow when leaving */
}
/* Animation when list items move */
.list-move {
transition: transform 0.5s;
}
</style>
(2) 要点:.list-move
CSS
/* When the position of a list item changes(As sorted),Apply Automatically .list-move */
.list-move {
transition: transform 0.5s;
}
(3) リストアニメーションの5つの主なシナリオ
| シーン | アニメーション |
|---|---|
| アイテムを追加 | フェードイン+スライドダウン |
| 項目を削除 | フェードアウト+左スワイプ |
| 並べ替え | 新しい位置へスムーズに移動 |
| フィルター | 削除されるアイテムはフェードアウト、残すアイテムはスムーズな遷移 |
| ドラッグ | マウスの動きをリアルタイムで追従 |
6. JavaScriptのフック
(1) 8つのJavaScriptフック
VUE
<template>
<Transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
:css="false" <!-- Disable CSS class -->
>
<p v-if="show">Hello</p>
</Transition>
</template>
<script setup>
import gsap from 'gsap'
function beforeEnter(el) {
console.log('Before enter:', el)
}
function enter(el, done) {
gsap.to(el, {
opacity: 1,
y: 0,
duration: 0.5,
onComplete: done // Notification Complete
})
}
function afterEnter(el) {
console.log('After enter:', el)
}
// leave / beforeLeave / afterLeave Similar
</script>
(2) GSAPとの連携(推奨)
BASH
npm install gsap
VUE
<template>
<Transition :css="false" @enter="onEnter" @leave="onLeave">
<p v-if="show">Hello GSAP</p>
</Transition>
</template>
<script setup>
import gsap from 'gsap'
function onEnter(el, done) {
gsap.fromTo(el,
{ opacity: 0, y: 50 },
{ opacity: 1, y: 0, duration: 0.5, onComplete: done }
)
}
function onLeave(el, done) {
gsap.to(el, { opacity: 0, y: -50, duration: 0.3, onComplete: done })
}
</script>
7. サードパーティ製のアニメーションライブラリ
(1) Animate.css の統合
BASH
npm install animate.css
JS
// main.js
import 'animate.css'
VUE
<template>
<Transition
enter-active-class="animate__animated animate__fadeIn"
leave-active-class="animate__animated animate__fadeOut"
>
<p v-if="show">Hello</p>
</Transition>
</template>
(2) @vueuse/motion
BASH
npm install @vueuse/motion
JS
// main.js
import { MotionPlugin } from '@vueuse/motion'
app.use(MotionPlugin)
VUE
<template>
<div v-motion :initial="{ opacity: 0, y: 50 }" :enter="{ opacity: 1, y: 0 }">
Fade in from below
</div>
</template>
(3) GSAPの推奨ユースケース
| ライブラリ | 評価 | 対象 |
|---|---|---|
| CSS アニメーション | ⭐⭐⭐⭐⭐ | シンプルなトランジション、フェード |
| Animate.css | ⭐⭐⭐⭐ | 多種多様なプリセットアニメーション |
| @vueuse/motion | ⭐⭐⭐⭐ | 宣言型で、Vueとの統合性に優れている |
| GSAP | ⭐⭐⭐⭐⭐ | 複雑なタイムライン、物理演算に基づくアニメーション |
8. 完全な事例:5つの主要な移行シナリオ
(1) ▶ サンプル:. CSSアニメーションの5つの種類
CSS
/* 1. Fade In, Fade Out */
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
/* 2. Slide */
.slide-enter-active, .slide-leave-active { transition: transform 0.3s; }
.slide-enter-from { transform: translateX(-100%); }
.slide-leave-to { transform: translateX(100%); }
/* 3. Zoom */
.scale-enter-active, .scale-leave-active { transition: transform 0.3s; }
.scale-enter-from, .scale-leave-to { transform: scale(0); }
/* 4. Rotation */
.rotate-enter-active { transition: transform 1s; }
.rotate-enter-from { transform: rotate(0deg); }
.rotate-leave-active { animation: spin 0.5s; }
/* 5. Combination */
.combo-enter-active, .combo-leave-active { transition: all 0.3s; }
.combo-enter-from { opacity: 0; transform: translateX(-50px) scale(0.8); }
(2) ▶ サンプル:. 6つのCSSクラスの詳細な説明
| クラス | トリガー |
|---|---|
.fade-enter-from |
要素を挿入する前に |
.fade-enter-active |
要素挿入プロセス |
.fade-enter-to |
要素を挿入した後 |
.fade-leave-from |
エレメントが去る前に |
.fade-leave-active |
要素の離脱プロセス |
.fade-leave-to |
『エレメントが去った後』 |
(3) ▶ サンプル:. TransitionGroup リストアニメーション
VUE
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</TransitionGroup>
<style>
.list-enter-active, .list-leave-active {
transition: all 0.5s;
}
.list-move { transition: transform 0.5s; }
</style>
(4) ▶ サンプル:. 主要なサードパーティ製アニメーションライブラリ5選
| ライブラリ | コマンド | 適用対象 |
|---|---|---|
| CSS | なし(組み込み) | シンプル |
| Animate.css | npm i animate.css |
プリセットアニメーション |
| @vueuse/motion | npm i @vueuse/motion |
宣言型 |
| GSAP | npm i gsap |
複雑なタイムライン |
| Motion One | npm i motion |
軽量なWebアニメーション |
(5) ▶ サンプル:. よくある5つの間違いに関するクイックリファレンス
| エラー | 症状 | 解決策 |
|---|---|---|
| 遷移が反映されない | 要素が即座に消える | <Transition> ラッパー + v-if を追加 |
| v-for にアニメーションなし | リスト項目間のトランジションなし | <TransitionGroup> を使用 |
| 並べ替え時にアニメーションが表示されない | 移動時にカクつきがある | .list-move クラスを追加 |
| 複数のコンポーネント間の同時切り替え | 重複 | 区別するために key を追加 + mode="out-in" |
| CSSアニメーションの速度が速すぎる/遅すぎる | ユーザー体験の低下 | トランジションの持続時間を0.2~0.5秒に調整する |
(6) ▶ サンプル:. 5つの実践的なシナリオ
| シーン | アニメーション |
|---|---|
| タブの切り替え | フェード(アウト→イン) |
| モーダルダイアログ | 拡大・縮小 + フェード |
| リストへの追加・削除 | リストのアニメーション |
| ルート切り替え | フェード+スライド |
| トースト通知 | 上からスライド表示 + 自動消去 |
❓ よくある質問
Q CSSトランジションとCSS @keyframesのどちらを選べばいいですか?
A 単純なトランジション(不透明度やトランスフォームなど)にはCSSトランジションを使用してください。複雑なアニメーション(多段階、物理演算ベースなど)には@keyframesまたはGSAPを使用してください。Vue Transitionsは両方をサポートしています。
Q TransitionGroup では :key セレクタが必要ですか?
A はい。
<TransitionGroup> 子要素は :key を使用して一意に識別する必要があります。そうしないと、アニメーションがトリガーされません。Q 「ページ遷移」アニメーションを実装するにはどうすればよいですか?
A
<router-view v-slot="{ Component }"> + <Transition> で囲んでください。ルートが変わるたびにコンポーネントが切り替わり、遷移がトリガーされます。Q
mode="out-in"?の目的は何ですか?A これは、表示を終了するコンポーネントのアニメーションが終了してから、表示を開始するコンポーネントのアニメーションが始まるようにするためのものです。これにより、両方のコンポーネントが同時に表示される(重なる)ことを防ぎます。
Q JavaScriptフックとCSSクラスは併用できますか?
A はい。
<Transition :css="false" @enter="onEnter"> CSSクラスを無効にして、JavaScriptフックのみを使用することもできます。あるいは、両方を有効にすることも可能です(スタイリングにはCSSクラスを、コールバックにはJavaScriptフックを使用します)。Q アニメーションの動作が遅い場合はどうすればよいですか?
A (1)
transform および opacity(GPU アクセラレーション対応)を使用する;(2) レイアウトをトリガーするプロパティ(width、height、top)の使用を避ける;(3) 同時にアニメーション処理される要素の数を減らす。Q VueでAnimate.cssを使うにはどうすればよいですか?
A
enter-active-class="animate__animated animate__fadeIn" を使用して、Animate.cssのクラス名をVueのフックにマッピングしてください。📖 まとめ
<Transition>要素を1つ追加または削除;6つのCSSクラスが自動的に管理されます<TransitionGroup>リストのアニメーション、.list-move並べ替え- 3つのモード:デフォルト(オーバーラップ)/アウト・イン(推奨)/イン・アウト
- CSSアニメーションの5つの種類:フェードイン/フェードアウト/スライド/拡大縮小/回転/組み合わせ
- 8つのJSフック:before-enter / enter / after-enter / before-leave / leave / after-leave
- 主要なサードパーティ製ライブラリ 5 つ:CSS / Animate.css / @vueuse/motion / GSAP / Motion One
- 5つの実践演習:タブの切り替え/モーダル/リスト/ルーティング/通知
📝 練習問題
(1) 基礎問題(難易度:⭐)
シンプルなフェードイン/フェードアウト機能を持つモーダルを実装する:
- ボタンをクリックしてモーダルを開く
- 0.3秒でフェードイン
- クリックして閉じる(フェードアウト)
- 背景マスクのフェードインとフェードアウトを同期させる
(2) 上級問題(難易度:⭐⭐)
TransitionGroup によるリストアニメーションを実装する:
- やるべきこと 5件
- 新しいアイテムをフェードインさせる(0.5秒)
- 削除された項目をフェードアウトさせる(0.5秒 + position: absolute)
- 並べ替え時に、その他の項目もスムーズに移動する (.list-move)
(3) チャレンジ問題(難易度:⭐⭐⭐)
完全な「ページ遷移アニメーション」システムを実装する:
- ルート切り替え時のフェード+スライドアニメーション
- リスト内の項目の追加、削除、並べ替えを行うための3種類のアニメーション
- モーダルポップアップにおける「拡大+フェード」の組み合わせ
- GSAPとの連携による複雑なタイムラインアニメーション
- 5つのサードパーティ製アニメーションライブラリの比較テスト
- パフォーマンスの最適化(GPU アクセラレーション + 変更予定)



