Skip to content

🎭 Transition トランジションアニメーション - インターフェースを活気づけよう!

🌟 アニメーション魔法使い:あなたのアプリに生命力を注入し、あらゆるインタラクションに驚きを与えましょう!

✨ Transition とは?

Transition は Vant が提供するトランジションアニメーションコンポーネントで、優雅なダンサーのように、要素の表示・非表示にスムーズなアニメーション効果を追加します。フェードイン/フェードアウト、スライド展開、スケール変換など、あらゆるアニメーションでインターフェースを生き生きとさせることができます!

🎯 主な特徴

  • 🎨 豊富なアニメーション:多くの組み込みトランジション効果
  • パフォーマンス最適化:CSS3 transform ベース、スムーズで滑らか
  • 🔧 使いやすい:1つのコンポーネントで全てのアニメーションニーズを解決
  • 🎛️ 高度なカスタマイズ:アニメーション時間とイージング関数のカスタマイズをサポート

🚀 クイックスタート

📦 基本的な使い方

最もシンプルなフェードイン/フェードアウト効果:

vue
<template>
  <div>
    <!-- 🎯 制御ボタン -->
    <van-button @click="show = !show" type="primary">
      {{ show ? '非表示' : '表示' }}
    </van-button>
    
    <!-- ✨ トランジションアニメーション -->
    <van-transition :show="show">
      <div class="content">
        🎉 Hello Vant Transition!
      </div>
    </van-transition>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const show = ref(false);
</script>

<style>
.content {
  width: 200px;
  height: 100px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  margin-top: 16px;
}
</style>

🎨 アニメーションの種類

🌟 組み込みアニメーション効果

Vant は豊富な組み込みアニメーション効果を提供しています:

アニメーション名効果の説明適用シーン
fadeフェードイン/フェードアウト🌅 汎用トランジション、優雅で自然
fade-up上方向へのフェード📱 モバイル端末向け、ジェスチャーに合わせる
fade-down下方向へのフェード🔽 ドロップダウンメニュー、通知など
fade-left左方向へのフェード⬅️ サイドバー、引き出しなど
fade-right右方向へのフェード➡️ コンテンツ切り替え、ナビゲーションなど
slide-up上方向へのスライド📋 ボトムポップアップ、操作パネル
slide-down下方向へのスライド📢 トップ通知、プルリフレッシュ
slide-left左方向へのスライド📄 ページ切り替え、カードスライド
slide-right右方向へのスライド🔄 戻る操作、サイドスライドメニュー

🎪 アニメーション効果のデモ

vue
<template>
  <div class="demo-container">
    <!-- 🎛️ アニメーションセレクタ -->
    <van-field
      v-model="selectedAnimation"
      is-link
      readonly
      label="アニメーションを選択"
      placeholder="アニメーション効果を選択してください"
      @click="showPicker = true"
    />
    
    <van-popup v-model:show="showPicker" position="bottom">
      <van-picker
        :columns="animationOptions"
        @confirm="onConfirm"
        @cancel="showPicker = false"
      />
    </van-popup>
    
    <!-- 🎯 制御ボタン -->
    <van-button 
      @click="show = !show" 
      type="primary" 
      block
      style="margin: 16px 0;"
    >
      {{ show ? 'アニメーションを非表示' : 'アニメーションを表示' }}
    </van-button>
    
    <!-- ✨ アニメーションデモエリア -->
    <div class="animation-stage">
      <van-transition :show="show" :name="selectedAnimation">
        <div class="demo-box">
          <div class="animation-name">{{ selectedAnimation }}</div>
          <div class="animation-desc">{{ getAnimationDesc(selectedAnimation) }}</div>
        </div>
      </van-transition>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const show = ref(false);
const showPicker = ref(false);
const selectedAnimation = ref('fade');

const animationOptions = [
  { text: 'フェードイン/フェードアウト (fade)', value: 'fade' },
  { text: '上方向へのフェード (fade-up)', value: 'fade-up' },
  { text: '下方向へのフェード (fade-down)', value: 'fade-down' },
  { text: '左方向へのフェード (fade-left)', value: 'fade-left' },
  { text: '右方向へのフェード (fade-right)', value: 'fade-right' },
  { text: '上方向へのスライド (slide-up)', value: 'slide-up' },
  { text: '下方向へのスライド (slide-down)', value: 'slide-down' },
  { text: '左方向へのスライド (slide-left)', value: 'slide-left' },
  { text: '右方向へのスライド (slide-right)', value: 'slide-right' },
];

const onConfirm = ({ selectedValues }) => {
  selectedAnimation.value = selectedValues[0];
  showPicker.value = false;
};

const getAnimationDesc = (name) => {
  const descriptions = {
    'fade': '🌅 優雅なフェードイン/フェードアウト',
    'fade-up': '📱 上方向へのフェード、モバイル端末向け',
    'fade-down': '🔽 下方向へのフェード、通知に最適',
    'fade-left': '⬅️ 左方向へのフェード、サイドバー専用',
    'fade-right': '➡️ 右方向へのフェード、コンテンツ切り替え',
    'slide-up': '📋 上方向へのスライド、ボトムポップアップ',
    'slide-down': '📢 下方向へのスライド、トップ通知',
    'slide-left': '📄 左方向へのスライド、ページ切り替え',
    'slide-right': '🔄 右方向へのスライド、戻る操作',
  };
  return descriptions[name] || '✨ 美しいアニメーション効果';
};
</script>

<style>
.demo-container {
  padding: 16px;
}

.animation-stage {
  min-height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f7f8fa;
  border-radius: 8px;
  margin-top: 16px;
}

.demo-box {
  width: 200px;
  height: 120px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}

.animation-name {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 8px;
}

.animation-desc {
  font-size: 12px;
  opacity: 0.8;
  text-align: center;
}
</style>

⚙️ 高度な設定

🎛️ アニメーションの長さをカスタマイズ

vue
<template>
  <div>
    <!-- 🐌 低速アニメーション (1秒) -->
    <van-transition :show="show1" :duration="1000">
      <div class="slow-box">低速アニメーション (1s)</div>
    </van-transition>
    
    <!-- ⚡ 高速アニメーション (200ms) -->
    <van-transition :show="show2" :duration="200">
      <div class="fast-box">高速アニメーション (0.2s)</div>
    </van-transition>
    
    <!-- 🎯 異なる表示/非表示の長さ -->
    <van-transition 
      :show="show3" 
      :duration="{ enter: 500, leave: 300 }"
    >
      <div class="custom-box">カスタム長さ</div>
    </van-transition>
  </div>
</template>

🎨 アニメーション効果をカスタマイズ

あなた独自のアニメーション効果を作成しましょう:

vue
<template>
  <van-transition :show="show" name="my-custom">
    <div class="custom-content">カスタムアニメーション</div>
  </van-transition>
</template>

<style>
/* 🎭 カスタムアニメーションクラス名 */
.my-custom-enter-active,
.my-custom-leave-active {
  transition: all 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.my-custom-enter-from {
  opacity: 0;
  transform: scale(0.8) rotate(-10deg);
}

.my-custom-leave-to {
  opacity: 0;
  transform: scale(1.2) rotate(10deg);
}

/* 🌟 効果を追加 */
.custom-content {
  background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
  color: white;
  padding: 20px;
  border-radius: 12px;
  text-align: center;
  box-shadow: 0 8px 32px rgba(255, 107, 107, 0.3);
}
</style>

🎪 実際の使用シーン

📱 モバイル端末向けポップアップ

vue
<template>
  <div>
    <!-- 🎯 トリガーボタン -->
    <van-button @click="showModal = true" type="primary" block>
      ポップアップを開く
    </van-button>
    
    <!-- 🌟 オーバーレイ -->
    <van-transition :show="showModal">
      <div class="modal-overlay" @click="showModal = false">
        <!-- 📋 ポップアップコンテンツ -->
        <van-transition :show="showModal" name="slide-up">
          <div class="modal-content" @click.stop>
            <div class="modal-header">
              <h3>🎉 美しいポップアップ</h3>
              <van-icon name="cross" @click="showModal = false" />
            </div>
            <div class="modal-body">
              <p>これは Transition コンポーネントを使用して作成されたポップアップの例です。</p>
              <p>スムーズなアニメーション効果と優れたユーザーエクスペリエンスを備えています。</p>
            </div>
            <div class="modal-footer">
              <van-button @click="showModal = false" type="default">
                キャンセル
              </van-button>
              <van-button @click="showModal = false" type="primary">
                確認
              </van-button>
            </div>
          </div>
        </van-transition>
      </div>
    </van-transition>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const showModal = ref(false);
</script>

<style>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: flex-end;
  z-index: 1000;
}

.modal-content {
  background: white;
  border-radius: 16px 16px 0 0;
  width: 100%;
  max-height: 70vh;
  overflow: hidden;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #eee;
}

.modal-body {
  padding: 20px;
  line-height: 1.6;
}

.modal-footer {
  padding: 16px 20px;
  display: flex;
  gap: 12px;
  border-top: 1px solid #eee;
}
</style>

🔄 ページ切り替えアニメーション

vue
<template>
  <div class="page-container">
    <!-- 🧭 ナビゲーションバー -->
    <van-nav-bar 
      :title="currentPage.title"
      left-arrow
      @click-left="goBack"
    />
    
    <!-- 📄 ページコンテンツ -->
    <div class="page-content">
      <van-transition 
        :show="true" 
        :name="transitionName"
        mode="out-in"
      >
        <component :is="currentPage.component" :key="currentPage.name" />
      </van-transition>
    </div>
    
    <!-- 🎯 ページ切り替えボタン -->
    <div class="page-controls">
      <van-button 
        v-for="page in pages" 
        :key="page.name"
        @click="navigateTo(page)"
        :type="currentPage.name === page.name ? 'primary' : 'default'"
        size="small"
      >
        {{ page.title }}
      </van-button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

const currentPageIndex = ref(0);
const transitionName = ref('slide-right');

const pages = [
  { name: 'home', title: 'ホーム', component: 'PageHome' },
  { name: 'about', title: '概要', component: 'PageAbout' },
  { name: 'contact', title: 'お問い合わせ', component: 'PageContact' },
];

const currentPage = computed(() => pages[currentPageIndex.value]);

const navigateTo = (page) => {
  const newIndex = pages.findIndex(p => p.name === page.name);
  const oldIndex = currentPageIndex.value;
  
  // 🎭 ナビゲーションの方向に応じてアニメーションを選択
  transitionName.value = newIndex > oldIndex ? 'slide-left' : 'slide-right';
  currentPageIndex.value = newIndex;
};

const goBack = () => {
  if (currentPageIndex.value > 0) {
    transitionName.value = 'slide-right';
    currentPageIndex.value--;
  }
};
</script>

🎯 API リファレンス

Props

パラメータ説明タイプデフォルト値
showコンポーネントを表示するかどうかbooleanfalse
nameアニメーションの種類string'fade'
durationアニメーションの長さ(ミリ秒)number | object300
appear初期レンダリング時にトランジションを使用するかどうかbooleanfalse

Events

イベント名説明コールバックパラメータ
before-enter表示前にトリガー-
enter表示中にトリガーel: Element
after-enter表示後にトリガー-
before-leave非表示前にトリガー-
leave非表示中にトリガーel: Element
after-leave非表示後にトリガー-

アニメーションの長さの設定

typescript
// 🕐 統一長さ
duration: 500

// 🎭 表示と非表示の長さを個別に設定
duration: {
  enter: 300,
  leave: 500
}

💡 ベストプラクティス

🎨 アニメーション選択ガイド

シーン推奨アニメーション理由
🔔 通知fade-down上部から自然に出現し、ユーザーの期待に合う
📋 ボトムポップアップslide-up下部からスライド表示、モバイル端末の標準操作
🎭 モーダルダイアログfadeシンプルで優雅、注意を分散させない
📄 ページ切り替えslide-left/right明確な方向性、ナビゲーション体験を向上
🎯 ツールチップfade-up軽量アニメーション、迅速な応答

⚡ パフォーマンス最適化のコツ

vue
<template>
  <!-- ✅ 推奨:v-show を Transition と組み合わせる -->
  <van-transition :show="visible">
    <div v-show="visible" class="content">コンテンツ</div>
  </van-transition>
  
  <!-- ❌ 避ける:頻繁な DOM の作成と破棄 -->
  <van-transition :show="visible">
    <div v-if="visible" class="content">コンテンツ</div>
  </van-transition>
</template>

<script setup>
// 🎯 適切なアニメーションの長さを使用
const duration = {
  enter: 250,  // 表示は少し速く、応答性を高める
  leave: 200   // 非表示はより速く、待ち時間を減らす
};

// 🔧 複雑すぎるアニメーションを避ける
const simpleTransition = 'fade';  // ✅ シンプルで効率的
const complexTransition = 'bounce-scale-rotate';  // ❌ 複雑すぎる
</script>

🎪 アニメーション組み合わせのコツ

vue
<template>
  <!-- 🌟 多層アニメーション効果 -->
  <van-transition :show="show" name="fade">
    <div class="container">
      <van-transition :show="show" name="slide-up" :duration="400">
        <div class="header">タイトルエリア</div>
      </van-transition>
      
      <van-transition :show="show" name="slide-up" :duration="500">
        <div class="content">コンテンツエリア</div>
      </van-transition>
      
      <van-transition :show="show" name="slide-up" :duration="600">
        <div class="footer">フッターエリア</div>
      </van-transition>
    </div>
  </van-transition>
</template>

🔧 よくある質問

❓ アニメーションが効かない?

🔍 チェックリスト

  1. show 属性が正しくバインドされているか確認
  2. ✅ CSS スタイルが上書きされていないか確認
  3. ✅ アニメーション名が正しいか検証
  4. ✅ 要素に明確なサイズが設定されているか確認
vue
<!-- ❌ 問題の例 -->
<van-transition :show="visible">
  <div style="display: none;">コンテンツ</div>  <!-- display: none はアニメーションを阻止する -->
</van-transition>

<!-- ✅ 正しい例 -->
<van-transition :show="visible">
  <div class="content">コンテンツ</div>
</van-transition>

❓ 複雑なアニメーションを実現するには?

vue
<template>
  <van-transition 
    :show="show" 
    name="custom-complex"
    @before-enter="onBeforeEnter"
    @enter="onEnter"
    @after-enter="onAfterEnter"
  >
    <div class="complex-element">複雑なアニメーション</div>
  </van-transition>
</template>

<script setup>
// 🎭 JavaScript フックを使用して複雑なアニメーションを実現
const onBeforeEnter = (el) => {
  el.style.opacity = '0';
  el.style.transform = 'scale(0.5) rotate(-180deg)';
};

const onEnter = (el) => {
  el.offsetHeight; // 再レイアウトをトリガー
  el.style.transition = 'all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
  el.style.opacity = '1';
  el.style.transform = 'scale(1) rotate(0deg)';
};

const onAfterEnter = (el) => {
  console.log('🎉 アニメーション完了!');
};
</script>

🌟 高度なテクニック

🎨 カスタムイージング関数

css
/* 🎭 独自のアニメーション感覚を作る */
.my-transition-enter-active {
  transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.my-transition-leave-active {
  transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}

/* 🌟 バウンス効果 */
.bounce-enter-active {
  animation: bounce-in 0.5s;
}

@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.1);
  }
  100% {
    transform: scale(1);
  }
}

🔄 アニメーションシーケンス

vue
<template>
  <div class="sequence-container">
    <van-transition 
      v-for="(item, index) in items" 
      :key="item.id"
      :show="show"
      name="slide-up"
      :duration="300"
      :style="{ transitionDelay: `${index * 100}ms` }"
    >
      <div class="sequence-item">{{ item.text }}</div>
    </van-transition>
  </div>
</template>

<script setup>
const items = [
  { id: 1, text: '最初の要素' },
  { id: 2, text: '2番目の要素' },
  { id: 3, text: '3番目の要素' },
];
</script>

関連ドキュメント 📚

🎯 コアコンポーネント

🎨 インタラクティブコンポーネント

🔔 フィードバックコンポーネント

  • Toast トースト - メッセージ提示、複数のトランジション効果を内蔵
  • Notify 通知 - トップ通知、スライドダウンアニメーションを使用
  • Loading ローディング - ローディング状態、フェードイン/フェードアウトをサポート

⚡ 高度な機能

Vant に基づく企業向けモバイルソリューション