Transitions & Animationen
Flüssige Übergänge und Animationen, die deine UI zum Leben erwecken – eingebaut in Vue.
Warum Transitions in Vue?
Vue bietet ein eingebautes Transition-System, das automatisch CSS-Klassen hinzufügt und entfernt, wenn Elemente erscheinen, verschwinden oder sich ändern. Kein manuelles Klassen-Togglen, keine requestAnimationFrame-Hacks – einfach <Transition> drumwickeln und fertig.
Die Transition-Komponente
<Transition> umwickelt ein einzelnes Element und fügt automatisch CSS-Klassen für Enter- und Leave-Phasen hinzu:
<script setup>
import { ref } from 'vue'
const sichtbar = ref(true)
</script>
<template>
<button @click="sichtbar = !sichtbar">Umschalten</button>
<Transition name="fade">
<p v-if="sichtbar">Hallo, ich fade ein und aus! 👋</p>
</Transition>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>Die 6 Transition-Klassen
Vue fügt automatisch diese Klassen hinzu:
Enter: *-enter-from → *-enter-active → *-enter-to
Leave: *-leave-from → *-leave-active → *-leave-to
Der name-Prop bestimmt das Prefix (hier: fade-).
Beliebte Transition-Patterns
Mit verschiedenen CSS-Properties und Timings erstellst du vielseitige Übergänge:
<style>
/* Slide-Down */
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from {
opacity: 0;
transform: translateY(-10px);
}
.slide-leave-to {
opacity: 0;
transform: translateY(10px);
}
/* Scale */
.scale-enter-active,
.scale-leave-active {
transition: all 0.2s ease;
}
.scale-enter-from,
.scale-leave-to {
opacity: 0;
transform: scale(0.9);
}
/* Slide-Fade (kombiniert) */
.slide-fade-enter-active {
transition: all 0.3s ease-out;
}
.slide-fade-leave-active {
transition: all 0.2s ease-in;
}
.slide-fade-enter-from {
opacity: 0;
transform: translateX(20px);
}
.slide-fade-leave-to {
opacity: 0;
transform: translateX(-20px);
}
</style>TransitionGroup für Listen
Für Listen mit dynamischen Einträgen gibt es <TransitionGroup>. Es animiert nicht nur Enter/Leave, sondern auch die Bewegung anderer Elemente mit der speziellen *-move-Klasse.
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, text: 'Erstes Element' },
{ id: 2, text: 'Zweites Element' },
{ id: 3, text: 'Drittes Element' },
])
let nextId = 4
function hinzufuegen() {
const index = Math.floor(Math.random() * (items.value.length + 1))
items.value.splice(index, 0, {
id: nextId++,
text: 'Element ' + (nextId - 1),
})
}
function entfernen(id: number) {
items.value = items.value.filter(item => item.id !== id)
}
</script>
<template>
<button @click="hinzufuegen">Hinzufügen</button>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id" @click="entfernen(item.id)">
{{ item.text }}
</li>
</TransitionGroup>
</template>
<style>
.list-enter-active,
.list-leave-active {
transition: all 0.4s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* FLIP-Animation für verbleibende Elemente */
.list-move {
transition: transform 0.4s ease;
}
/* Leave-Elemente aus dem Flow nehmen */
.list-leave-active {
position: absolute;
}
</style>Der move-Trick
Die *-move-Klasse nutzt die FLIP-Technik (First, Last, Invert, Play). Vue berechnet automatisch die Position vor und nach der Änderung und animiert den Unterschied. Vergiss nicht, Leave-Elemente mit position: absolute aus dem Flow zu nehmen!
JavaScript-Hooks
Für komplexere Animationen kannst du JavaScript-Hooks verwenden – perfekt für berechnete Werte, gestaffelte Animationen oder die Web Animations API:
<template>
<TransitionGroup
@before-enter="vorEintritt"
@enter="eintritt"
@leave="austritt"
:css="false"
>
<div v-for="(item, i) in items" :key="item.id" :data-index="i">
{{ item.text }}
</div>
</TransitionGroup>
</template>
<script setup>
function vorEintritt(el) {
el.style.opacity = 0
el.style.transform = 'translateY(20px)'
}
function eintritt(el, done) {
// Gestaffelte Animation basierend auf Index
const delay = el.dataset.index * 100
el.animate([
{ opacity: 0, transform: 'translateY(20px)' },
{ opacity: 1, transform: 'translateY(0)' },
], {
duration: 400,
delay,
easing: 'ease-out',
fill: 'forwards',
}).onfinish = done
}
function austritt(el, done) {
el.animate([
{ opacity: 1, transform: 'scale(1)' },
{ opacity: 0, transform: 'scale(0.8)' },
], {
duration: 200,
easing: 'ease-in',
}).onfinish = done
}
</script>:css='false'
Setze :css="false", wenn du Animationen komplett in JavaScript steuerst. Das verhindert, dass Vue nach CSS-Klassen sucht, und gibt dir volle Kontrolle über Timing und done()-Callbacks.
Animation beim ersten Laden
Mit dem appear-Prop animierst du Elemente auch beim initialen Rendering:
<Transition name="fade" appear>
<div class="hero-section">
<h1>Willkommen!</h1>
</div>
</Transition>
<!-- Eigene Appear-Klassen -->
<Transition
appear
appear-from-class="opacity-0 scale-90"
appear-active-class="transition duration-500 ease-out"
appear-to-class="opacity-100 scale-100"
>
<div>Animiert beim Laden</div>
</Transition>State-getriebene Animationen
Nicht alle Animationen brauchen <Transition>. Für kontinuierliche, datengesteuerte Animationen nutze CSS-Transitions direkt mit reaktiven Werten:
<script setup>
import { ref, computed } from 'vue'
const fortschritt = ref(0)
const balkenStyle = computed(() => ({
width: fortschritt.value + '%',
transition: 'width 0.5s ease',
}))
</script>
<template>
<input type="range" v-model.number="fortschritt" min="0" max="100" />
<div class="h-4 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-emerald-500 rounded-full" :style="balkenStyle" />
</div>
</template>Rails-Vergleich: Turbo Morphing vs. Vue Transitions
Von Turbo zu Vue
In Rails 7+ nutzt Turbo Morphing idiomorph, um DOM-Änderungen zu minimieren. Das ist clever, aber es gibt dir kaum Kontrolle über wie die Änderung visuell passiert.
Vue's Transition-System ist grundlegend anders: Du definierst explizit, wie Elemente erscheinen, verschwinden und sich bewegen. Statt „der DOM ändert sich möglichst unsichtbar" sagst du „zeige dem User die Änderung mit dieser Animation".
Turbo: Unsichtbare DOM-Diffs · Vue: Sichtbare, kontrollierte Übergänge
Third-Party Animations
Vue's Transition-Klassen lassen sich hervorragend mit Bibliotheken wie Animate.css oder Motion One kombinieren:
<!-- Mit Animate.css -->
<Transition
enter-active-class="animate__animated animate__fadeInUp"
leave-active-class="animate__animated animate__fadeOutDown"
>
<div v-if="sichtbar">Animiert mit Animate.css</div>
</Transition>
<!-- Mit @vueuse/motion -->
<script setup>
import { useMotion } from '@vueuse/motion'
const zielRef = ref(null)
useMotion(zielRef, {
initial: { opacity: 0, y: 50 },
enter: { opacity: 1, y: 0, transition: { duration: 500 } },
})
</script>
<template>
<div ref="zielRef">Smooth entrance!</div>
</template>Empfehlung
Für einfache Transitions reichen Vue's eingebaute CSS-Klassen völlig aus. Greife nur zu Bibliotheken, wenn du komplexe Choreographien, physikbasierte Animationen oder Spring-Dynamics brauchst.
Live-Demo: Animierte To-Do-Liste
- 🛒 Einkaufen gehen
- 📧 Emails beantworten
- 💻 Vue Tutorial durcharbeiten
3 Items · Klicke ✕ zum Entfernen oder nutze die Buttons oben.