Skip to content

Motion

Motion in User Interfaces ist mehr als Dekoration – sie ist ein wesentliches Gestaltungsmittel, das Verständnis fördert, Feedback gibt und emotionale Bindung schafft. Celestia definiert Motion-Prinzipien für subtile, zweckmässige Animationen.

Jede Animation in Celestia hat einen klaren Zweck:

Orientierung:

  • Zeigt, woher Elemente kommen und wohin sie gehen
  • Macht räumliche Beziehungen verständlich
  • Verhindert Desorientierung bei Kontextwechseln

Feedback:

  • Bestätigt Benutzeraktionen
  • Signalisiert Systemzustände (Laden, Erfolg, Fehler)
  • Macht Interfaces reaktionsfreudiger

Hierarchie:

  • Lenkt Aufmerksamkeit auf wichtige Elemente
  • Unterstützt die Informationsstruktur
  • Führt den Blick des Nutzers

Emotion:

  • Schafft Freude bei der Interaktion
  • Verleiht der Marke Persönlichkeit
  • Macht technische Abläufe menschlicher

Celestia-Animationen sind dezent und nicht aufdringlich:

  • Kurze Dauern (meist unter 500ms)
  • Sanfte Easing-Funktionen
  • Konsistente Bewegungsmuster
  • Respekt vor Nutzerpräferenzen (Reduced Motion)

Die Dauer einer Animation hängt von ihrer Komplexität und dem Kontext ab:

KategorieDauerVerwendung
Fast100-150msMicro-interactions (Hover, Focus)
Normal200-300msStandard-Übergänge
Slow300-500msKomplexe Animationen, Page-Transitions

Design Tokens:

--animation-duration-fast: 150ms;
--animation-duration-normal: 250ms;
--animation-duration-slow: 400ms;

Fast (100-150ms):

  • Button-Hover
  • Link-Hover
  • Focus-States
  • Toggle-Switches
  • Icon-Animationen

Normal (200-300ms):

  • Dropdown-Öffnen
  • Modal-Öffnen/Schliessen
  • Accordion
  • Tabs-Wechsel
  • Formular-Validierung

Slow (300-500ms):

  • Page-Transitions
  • Sidebar ein-/ausblenden
  • Loading-Animationen
  • Onboarding-Touren
  • Toast-Notifications

Easing-Funktionen bestimmen, wie eine Animation beschleunigt oder verzögert wird. Sie verleihen Bewegungen natürliche Physik.

Default (ease-out):

--animation-easing-default: cubic-bezier(0.4, 0, 0.2, 1);
  • Schnell starten, langsam auslaufen
  • Für die meisten UI-Animationen
  • Natürliches Gefühl

Enter (decelerate):

--animation-easing-enter: cubic-bezier(0, 0, 0.2, 1);
  • Elemente erscheinen (Enter)
  • Modals, Dropdowns, Popovers
  • Sanftes Hereingleiten

Exit (accelerate):

--animation-easing-exit: cubic-bezier(0.4, 0, 1, 1);
  • Elemente verschwinden (Exit)
  • Schnelles Entfernen
  • Weniger prominent als Enter

Bounce (overshoot):

--animation-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  • Spielerisch, aufmerksamkeitsstark
  • Für Erfolgszustände
  • Sparsam einsetzen
/* Standard-Übergang */
.button {
transition: all var(--animation-duration-fast) var(--animation-easing-default);
}
/* Element erscheint */
.modal {
animation: fadeIn var(--animation-duration-normal)
var(--animation-easing-enter);
}
/* Element verschwindet */
.toast.hide {
animation: slideOut var(--animation-duration-fast)
var(--animation-easing-exit);
}

Verwendung: Subtile Übergänge, Content-Wechsel

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.element {
animation: fadeIn var(--animation-duration-normal)
var(--animation-easing-enter);
}

Verwendung: Seitliche Bewegungen, Drawers, Toasts

@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideInBottom {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}

Verwendung: Modals, Popovers, Hervorhebungen

@keyframes scaleIn {
from {
transform: scale(0.95);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.modal {
animation: scaleIn var(--animation-duration-normal)
var(--animation-easing-enter);
}

Verwendung: Loading-Indikatoren, Icons

@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loading-spinner {
animation: spin 1s linear infinite;
}

Verwendung: Fehler, Invalid Input

@keyframes shake {
0%,
100% {
transform: translateX(0);
}
10%,
30%,
50%,
70%,
90% {
transform: translateX(-4px);
}
20%,
40%,
60%,
80% {
transform: translateX(4px);
}
}
.input-error {
animation: shake var(--animation-duration-normal)
var(--animation-easing-default);
}

Micro-Interactions sind subtile Animationen bei einzelnen UI-Elementen:

Buttons:

.button {
background: var(--color-primary);
transform: translateY(0);
transition:
background var(--animation-duration-fast) var(--animation-easing-default),
transform var(--animation-duration-fast) var(--animation-easing-default);
}
.button:hover {
background: var(--color-primary-hover);
transform: translateY(-1px);
}
.button:active {
transform: translateY(0);
}

Links:

.link {
position: relative;
text-decoration: none;
}
.link::after {
content: "";
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: currentColor;
transition: width var(--animation-duration-fast)
var(--animation-easing-default);
}
.link:hover::after {
width: 100%;
}

Sichtbare Fokus-Indikatoren mit Animation:

.interactive-element:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--color-focus-ring);
transition: box-shadow var(--animation-duration-fast)
var(--animation-easing-default);
}

Button Loading:

.button--loading {
position: relative;
color: transparent;
}
.button--loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}

Skeleton Loading:

.skeleton {
background: linear-gradient(
90deg,
var(--color-bg-muted) 25%,
var(--color-bg-subtle) 50%,
var(--color-bg-muted) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.toggle {
width: 48px;
height: 24px;
background: var(--color-bg-muted);
border-radius: 12px;
position: relative;
cursor: pointer;
transition: background var(--animation-duration-fast)
var(--animation-easing-default);
}
.toggle-handle {
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
position: absolute;
top: 2px;
left: 2px;
transition: transform var(--animation-duration-fast)
var(--animation-easing-bounce);
}
.toggle-active {
background: var(--color-primary);
}
.toggle-active .toggle-handle {
transform: translateX(24px);
}

Moderner Ansatz für Page Transitions in Astro:

layout.astro
<!DOCTYPE html>
<html lang="de">
<head>
<style>
@view-transition {
navigation: auto;
}
</style>
</head>
<body>
<slot />
</body>
</html>
.page-transition-enter {
opacity: 0;
transform: translateY(20px);
}
.page-transition-enter-active {
opacity: 1;
transform: translateY(0);
transition:
opacity var(--animation-duration-slow) var(--animation-easing-enter),
transform var(--animation-duration-slow) var(--animation-easing-enter);
}
.page-transition-exit {
opacity: 1;
}
.page-transition-exit-active {
opacity: 0;
transition: opacity var(--animation-duration-fast)
var(--animation-easing-exit);
}

Animationen müssen flüssig sein:

  • Verwenden Sie transform und opacity (GPU-beschleunigt)
  • Vermeiden Sie Animationen von width, height, top, left
  • Nutzen Sie will-change sparsam

Gut (GPU-beschleunigt):

.element {
transform: translateX(100px);
opacity: 0.5;
}

Schlecht (Layout-Trigger):

.element {
left: 100px;
width: 200px;
}
/* Vor der Animation */
.element {
will-change: transform, opacity;
}
/* Nach der Animation */
.element {
will-change: auto;
}

Respektieren Sie Nutzerpräferenzen:

@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}

Alternative für Reduced Motion:

@media (prefers-reduced-motion: reduce) {
.modal {
animation: none;
opacity: 1;
}
.dropdown {
transition: none;
}
}

Celestia respektiert prefers-reduced-motion:

  • Alle Animationen werden bei Aktivierung deaktiviert
  • Instant-States statt Übergänge
  • Keine automatisch abspielenden Animationen

Animationen dürfen den Fokus nicht beeinträchtigen:

  • Fokus muss sichtbar bleiben
  • Fokus-Verlust bei Animationen vermeiden
  • Fokus-Trap in Modals mit Animation

Zu viel Animation kann ablenken:

  • Maximal eine Animation gleichzeitig
  • Keine dauerhaft animierenden Elemente (ausser Loading)
  • Vermeidung von blinkenden oder flackernden Effekten

Zu lange Animationen:

  • ❌ Animationen über 500ms (ausser Page Transitions)
  • ❌ Unnötige Verzögerungen

Zu viele gleichzeitige Animationen:

  • ❌ Mehrere Elemente, die gleichzeitig animieren
  • ❌ Kaskadierende Animationen ohne Nutzen

Ablenkende Animationen:

  • ❌ Autoplay-Animationen, die nicht stoppen
  • ❌ Blinkende oder flackernde Effekte
  • ❌ Übertriebene Bounce-Effekte

Performance-Probleme:

  • ❌ Animation von Layout-Eigenschaften
  • ❌ Animation während Scroll-Events
  • ❌ Zu viele parallele Animationen

Inkonsistenz:

  • ❌ Verschiedene Dauern für ähnliche Animationen
  • ❌ Gemischte Easing-Funktionen ohne Konzept
  • Definierte Dauern und Easing verwenden
  • Konsistente Animationen für ähnliche Aktionen
  • Reduced Motion respektieren
  • Performance-Optimierung (transform, opacity)
  • Natürliche Physik (Easing-Funktionen)
  • Zweckmässigkeit prüfen
  • Subtilität bevorzugen
  • Animation um der Animation willen
  • Lange Dauern (> 500ms für UI)
  • Layout-Properties animieren
  • Reduced Motion ignorieren
  • Kognitive Überlastung durch Bewegung
  • Autoplay ohne Pause-Möglichkeit

Beispiel: Vollständige Motion-Implementation

Section titled “Beispiel: Vollständige Motion-Implementation”
:root {
/* Durations */
--animation-duration-fast: 150ms;
--animation-duration-normal: 250ms;
--animation-duration-slow: 400ms;
/* Easings */
--animation-easing-default: cubic-bezier(0.4, 0, 0.2, 1);
--animation-easing-enter: cubic-bezier(0, 0, 0.2, 1);
--animation-easing-exit: cubic-bezier(0.4, 0, 1, 1);
--animation-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
/* Button mit Hover-Animation */
.button {
transition:
background-color var(--animation-duration-fast)
var(--animation-easing-default),
transform var(--animation-duration-fast) var(--animation-easing-default),
box-shadow var(--animation-duration-fast) var(--animation-easing-default);
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.button:active {
transform: translateY(0);
transition-duration: 100ms;
}
/* Modal mit Scale-Animation */
.modal {
animation: scaleIn var(--animation-duration-normal)
var(--animation-easing-enter);
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Reduced Motion Support */
@media (prefers-reduced-motion: reduce) {
.button,
.modal {
transition: none;
animation: none;
}
}

Motion ist ein mächtiges Werkzeug im Design-Toolkit. Wenn sie subtil, zweckmässig und respektvoll eingesetzt wird, verbessert sie das Nutzererlebnis erheblich. Die Kunst liegt in der Zurückhaltung.