UNPKG

@casoon/dragonfly

Version:

Modular, lightweight CSS framework and design system for modern web projects. Optimized for Astro JS, LightningCSS and Container Queries with @layer-based architecture and comprehensive accessibility.

1,544 lines (1,282 loc) 53 kB
/** * Animation-Effekte * * Diese Datei enthält verschiedene Animation-Effekte für moderne UIs. * Die Effekte sind performant optimiert und berücksichtigen reduzierte Bewegung. * * Includes shared UI animations for common use across components (fadeIn, slideIn, spin, pulse, etc.) * Previously separate shared-ui-animations.css has been merged into this file. */ /* Basis-Keyframes */ @keyframes fade-in { from { opacity: var(--opacity-0); } to { opacity: var(--opacity-100); } } @keyframes fade-out { from { opacity: var(--opacity-100); } to { opacity: var(--opacity-0); } } @keyframes scale-in { from { opacity: var(--opacity-0); transform: scale(var(--scale-sm, 0.95)); } to { opacity: var(--opacity-100); transform: var(--transform-scale-100); } } @keyframes slide-in-up { from { opacity: var(--opacity-0); transform: translateY(var(--slide-distance, var(--move-md, var(--spacing-4)))); } to { opacity: var(--opacity-100); transform: translateX(0%); } } @keyframes slide-in-down { from { opacity: var(--opacity-0); transform: translateY(calc(-1 * var(--slide-distance, var(--move-md, var(--spacing-4))))); } to { opacity: var(--opacity-100); transform: translateX(0%); } } @keyframes slide-in-left { from { opacity: var(--opacity-0); transform: translateX(calc(-1 * var(--slide-distance, var(--move-md, var(--spacing-4))))); } to { opacity: var(--opacity-100); transform: translateX(0%); } } @keyframes slide-in-right { from { opacity: var(--opacity-0); transform: translateX(var(--slide-distance, var(--move-md, var(--spacing-4)))); } to { opacity: var(--opacity-100); transform: translateX(0%); } } @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateX(0%); } 40% { transform: translateY(calc(-1 * var(--bounce-height, 25%))); } 60% { transform: translateY(calc(-1 * var(--bounce-height, 25%) / 2)); } } @keyframes pulse { 0%, 100% { opacity: var(--opacity-100); } 50% { opacity: var(--pulse-opacity-min, 0.5); } } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes ping { 0% { opacity: var(--opacity-100); transform: var(--transform-scale-100); } 75%, 100% { opacity: var(--opacity-0); transform: scale(var(--ping-scale, 2)); } } @keyframes wiggle { 0%, 100% { transform: rotate(0deg); } 25% { transform: rotate(var(--wiggle-angle, 3deg)); } 75% { transform: rotate(calc(-1 * var(--wiggle-angle, 3deg))); } } @keyframes float { 0%, 100% { transform: translateX(0%); } 50% { transform: translateY(calc(-1 * var(--float-distance, var(--spacing-2-5)))); } } @keyframes shake { 0%, 100% { transform: translateX(0%); } 10%, 30%, 50%, 70%, 90% { transform: translateX(calc(-1 * var(--shake-distance, var(--shake-distance-sm, var(--border-width))))); } 20%, 40%, 60%, 80% { transform: translateX(var(--shake-distance, var(--shake-distance-sm, var(--border-width)))); } } @keyframes heartbeat { 0%, 100% { transform: var(--transform-scale-100); } 14% { transform: scale(var(--heartbeat-scale, 1.3)); } 28% { transform: var(--transform-scale-100); } 42% { transform: scale(var(--heartbeat-scale, 1.3)); } 70% { transform: var(--transform-scale-100); } } @keyframes elastic { 0% { transform: scale(1, 1); } 12.5% { transform: scale(var(--elastic-scale-x-large, 1.25), var(--elastic-scale-y-small, 0.75)); } 25% { transform: scale(var(--elastic-scale-x-small, 0.75), var(--elastic-scale-y-large, 1.25)); } 37.5% { transform: scale(var(--elastic-scale-x-medium, 1.15), var(--elastic-scale-y-medium, 0.85)); } 50% { transform: scale(var(--elastic-scale-x-tiny, 0.95), var(--elastic-scale-y-tiny, 1.05)); } 62.5% { transform: scale(var(--elastic-scale-x-mini, 1.05), var(--elastic-scale-y-mini, 0.95)); } 75% { transform: scale(0.985, 1.015); } 87.5% { transform: scale(1.01, 0.99); } 100% { transform: scale(1, 1); } } @keyframes dialog-enter { from { opacity: var(--opacity-0); transform: var(--transform-scale-95) translateY(var(--dialog-offset, calc(-1 * var(--spacing-5)))); } to { opacity: var(--opacity-100); transform: var(--transform-scale-100) translateY(0%); } } @keyframes dialog-exit { from { opacity: var(--opacity-100); transform: var(--transform-scale-100); } to { opacity: var(--opacity-0); transform: var(--transform-scale-95) translateY(var(--dialog-offset, calc(-1 * var(--spacing-5)))); } } @keyframes focus-pulse { 0% { box-shadow: 0 0 0 0 var(--focus-color, rgb(66 153 225 / 60%)); } 70% { box-shadow: 0 0 0 var(--focus-ring-size, var(--spacing-1)) transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } @layer animations { :root { /* Durations */ --animation-duration-fastest: 100ms; --animation-duration-fast: 150ms; --animation-duration-normal: 300ms; --animation-duration-slow: 500ms; --animation-duration-slower: 750ms; --animation-duration-slowest: 1000ms; /* Timing Functions */ --ease-linear: linear; --ease-in: cubic-bezier(0.4, 0, 1, 1); --easing-decelerate: cubic-bezier(0, 0, 0.2, 1); --easing-smooth: cubic-bezier(0.4, 0, 0.2, 1); --easing-smooth-cubic: cubic-bezier(0.645, 0.045, 0.355, 1); --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55); --ease-spring: cubic-bezier(0.68, -0.6, 0.32, 1.6); /* Movement */ --move-xs: var(--spacing-1); --move-sm: var(--spacing-2); --move-md: var(--spacing-4); --move-lg: calc(var(--spacing-2) + var(--spacing-1)); --move-xl: 36px; /* Animation-spezifische Parameter */ --slide-distance: var(--move-md); --scroll-slide-distance: var(--spacing-7-5); --scroll-slide-from-edge: 100; /* Scale */ --scale-xs: 0.98; --scale-sm: 0.95; --scale-md: 0.9; --scale-lg: 1.05; --scale-xl: 1.1; /* Delay */ --delay-xs: 50ms; --delay-sm: 100ms; --delay-md: 200ms; --delay-lg: 300ms; --delay-xl: 500ms; /* Iterations */ --iteration-once: 1; --iteration-twice: 2; --iteration-thrice: 3; --iteration-infinite: infinite; /* Animation-spezifische Parameter */ --bounce-height: var(--percentage-25); --pulse-opacity-min: 0.5; --ping-scale: 2; --wiggle-angle: 3deg; --float-distance: var(--spacing-2-5); --shake-distance-sm: var(--border-width); --shake-distance-md: var(--border-width-thick); --shake-distance-lg: var(--spacing-1); --heartbeat-scale: 1.3; --elastic-scale-x-large: 1.25; --elastic-scale-y-small: 0.75; --elastic-scale-x-small: 0.75; --elastic-scale-y-large: 1.25; --elastic-scale-x-medium: 1.15; --elastic-scale-y-medium: 0.85; --elastic-scale-x-tiny: 0.95; --elastic-scale-y-tiny: 1.05; --elastic-scale-x-mini: 1.05; --elastic-scale-y-mini: 0.95; /* Dialog-Animation Parameter */ --dialog-offset: -var(--spacing-5); --dialog-duration: 250ms; --dialog-backdrop-opacity: var(--opacity-0).5; /* Fokus-Animation Parameter */ --focus-color: rgb(66 153 225 / 60%); --focus-ring-size: var(--spacing-1); --focus-animation-duration: var(--animation-duration-slower); /* Gestaffelte Animationen */ --stagger-base-delay: 50ms; --stagger-increment: 50ms; --stagger-max-delay: 1000ms; /* Backdrop Parameter */ --backdrop-opacity: var(--opacity-0).75; --backdrop-blur: 0; --backdrop-bg-color: rgb(0 0 0 / var(--backdrop-opacity)); --backdrop-animation-duration: var(--animation-duration-normal); /* UI Component Animation Tokens */ --ui-fade-in-animation: fadeIn var(--animation-duration-normal) var(--easing-decelerate); --ui-fade-out-animation: fadeOut var(--animation-duration-normal) var(--easing-decelerate); --ui-slide-in-animation: slideIn var(--animation-duration-normal) var(--easing-decelerate); --ui-slide-out-animation: slideOut var(--animation-duration-normal) var(--easing-decelerate); --ui-slide-up-animation: slideUp var(--animation-duration-normal) var(--easing-decelerate); --ui-slide-in-spring-animation: slideIn var(--animation-duration-normal) var(--ease-spring) forwards; /* Loading & Progress Animations */ --ui-spin-animation: spin var(--animation-duration-slowest) var(--ease-linear) infinite; --ui-pulse-animation: pulse var(--animation-duration-slowest) var(--easing-smooth) infinite; --ui-pulse-slow-animation: pulse 2s infinite; --ui-loading-animation: loading var(--animation-duration-slowest) infinite; --ui-progress-animation: progressIndeterminate var(--animation-duration-slowest) infinite; --ui-progress-stripes-animation: progressStripes var(--animation-duration-slowest) var(--ease-linear) infinite; /* Component-Specific Animations */ --ui-notification-timer-animation: notification-timer 5s var(--ease-linear) forwards; --ui-typing-animation: typingAnimation 1.4s infinite; --ui-search-spin-animation: searchSpin var(--animation-duration-slowest) var(--ease-linear) infinite; /* Toast & Modal Animations */ --ui-toast-enter-animation: var(--ui-slide-in-animation); --ui-toast-exit-animation: var(--ui-slide-out-animation); --ui-modal-backdrop-animation: var(--ui-fade-in-animation); --ui-modal-content-animation: var(--ui-slide-up-animation); /* Aktiviert Interpolation zwischen Keywords wie small, medium, large */ interpolate-size: allow-keywords; } /** * ========================================== * Animation Utility-Klassen * ========================================== */ /* Animation Basis-Utility */ @layer animation-base { .animate { animation-duration: var(--animation-duration-normal); animation-fill-mode: both; animation-timing-function: var(--easing-smooth); } } /* Animation Richtungs-Utilities */ @layer animation-direction { .direction-normal { animation-direction: normal; } .direction-reverse { animation-direction: reverse; } .direction-alternate { animation-direction: alternate; } .direction-alternate-reverse { animation-direction: alternate-reverse; } } /* Animation Fill-Mode Utilities */ @layer animation-fill { .fill-none { animation-fill-mode: none; } .fill-forwards { animation-fill-mode: forwards; } .fill-backwards { animation-fill-mode: backwards; } .fill-both { animation-fill-mode: both; } } /* Animation Iterations-Utilities */ @layer animation-iterations { .iteration-once, .once { animation-iteration-count: var(--iteration-once); } .iteration-twice, .twice { animation-iteration-count: var(--iteration-twice); } .iteration-thrice, .thrice { animation-iteration-count: var(--iteration-thrice); } .iteration-infinite, .infinite { animation-iteration-count: var(--iteration-infinite); } } /* Animation Delay-Utilities */ @layer animation-delay { .delay-xs { animation-delay: var(--delay-xs); } .delay-sm { animation-delay: var(--delay-sm); } .delay-md { animation-delay: var(--delay-md); } .delay-lg { animation-delay: var(--delay-lg); } .delay-xl { animation-delay: var(--delay-xl); } } /* Animation Duration-Utilities */ @layer animation-duration { .duration-fastest { animation-duration: var(--animation-duration-fastest); } .duration-fast { animation-duration: var(--animation-duration-fast); } .duration-normal { animation-duration: var(--animation-duration-normal); } .duration-slow { animation-duration: var(--animation-duration-slow); } .duration-slower { animation-duration: var(--animation-duration-slower); } .duration-slowest { animation-duration: var(--animation-duration-slowest); } } /** * ========================================== * Barrierefreiheit Motion-Utilities * ========================================== */ @layer motion-preferences { /* Aktiviert Animationen nur, wenn keine reduzierten Bewegungen bevorzugt werden */ .motion-safe { /* Standardmäßig keine Animationen/Übergänge */ animation: var(--animation-none) !important; transition: var(--transition-none) !important; } /* Für reduzierte Bewegung optimierte Stile */ .motion-reduce { /* Deaktiviert in Standardmodus */ display: none; } /* Bei aktivierter Bewegung: motion-safe aktivieren, motion-reduce deaktivieren */ @media (prefers-reduced-motion: no-preference) { .motion-safe { /* Animation- und Transition-Eigenschaften wiederherstellen */ animation: unset !important; transition: unset !important; } .motion-reduce { display: none; } } /* Bei reduzierter Bewegung: motion-safe deaktivieren, motion-reduce aktivieren */ @media (prefers-reduced-motion: reduce) { .motion-safe { /* Animation- und Transition-Eigenschaften deaktivieren */ animation: var(--animation-none) !important; transition: var(--transition-none) !important; } .motion-reduce { display: revert; } } } /** * ========================================== * Effekt-Animationen * ========================================== */ /* Einblend-Animationen */ @layer fade-animations { .fade-in { animation-name: fade-in; } .fade-out { animation-name: fade-out; } } /* Slide-Animationen */ @layer slide-animations { .slide-in-up { animation-name: slide-in-up; } .slide-in-down { animation-name: slide-in-down; } .slide-in-left { animation-name: slide-in-left; } .slide-in-right { animation-name: slide-in-right; } } /* Scale-Animationen */ @layer scale-animations { .scale-in { animation-name: scale-in; } .scale-out { animation-direction: reverse; animation-name: scale-in; } } /* Scroll-Animationen */ @layer scroll-animations { .scroll-fade-in { animation: fade-in var(--animation-duration-normal) var(--easing-decelerate) forwards; animation-range: entry 10 cover 30; animation-timeline: view(); opacity: var(--opacity-0); will-change: opacity; } .scroll-slide-in-up { animation: slide-in-up var(--animation-duration-normal) var(--easing-decelerate) forwards; animation-range: entry 10 cover 30; animation-timeline: view(); opacity: var(--opacity-0); transform: translateY(var(--scroll-slide-distance)); will-change: transform, opacity; } .scroll-slide-in-left { animation: slide-in-left var(--animation-duration-normal) var(--easing-decelerate) forwards; animation-range: entry 10 cover 30; animation-timeline: view(); opacity: var(--opacity-0); transform: translateX(calc(-1 * var(--scroll-slide-distance))); will-change: transform, opacity; } .scroll-slide-in-right { animation: slide-in-right var(--animation-duration-normal) var(--easing-decelerate) forwards; animation-range: entry 10 cover 30; animation-timeline: view(); opacity: var(--opacity-0); transform: translateX(var(--scroll-slide-distance)); will-change: transform, opacity; } } /* Interaktions-Animationen */ @layer interaction-animations { .interaction-scale { transition: transform var(--animation-duration-fast) var(--easing-decelerate); } .interaction-scale:active { transform: scale(var(--scale-xs)); } .hover-glow { transition: box-shadow var(--animation-duration-normal) var(--easing-decelerate); } .hover-glow:hover { box-shadow: 0 0 var(--spacing-2-5) var(--color-primary-500, rgb(0 123 255 / 50%)); } .tap-feedback { overflow: hidden; position: relative; } .tap-feedback:active::after { background-color: currentColor; content: ""; height: 100%; left: 0%; opacity: var(--opacity-10); pointer-events: none; position: absolute; top: 0%; width: 100%; } } /* Transition-Utilities */ @layer transition-utilities { .transition-opacity { transition-duration: var(--animation-duration-normal); transition-property: opacity; transition-timing-function: var(--easing-smooth); } .transition-transform { transition-duration: var(--animation-duration-normal); transition-property: transform; transition-timing-function: var(--easing-smooth); } .transition-shadow { transition-duration: var(--animation-duration-normal); transition-property: box-shadow; transition-timing-function: var(--easing-smooth); } .transition-colors { transition-duration: var(--animation-duration-normal); transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-timing-function: var(--easing-smooth); } .transition-all { transition-duration: var(--animation-duration-normal); transition-property: all; transition-timing-function: var(--easing-smooth); } } /* Komplexe Animationen */ @layer complex-animations { .animate-bounce { animation: bounce var(--animation-duration-slow) var(--easing-smooth) infinite; } .animate-pulse { animation: pulse var(--animation-duration-slower) var(--easing-smooth) infinite; } .animate-spin { animation: spin var(--animation-duration-slowest) var(--ease-linear) infinite; } .animate-ping { animation: ping var(--animation-duration-slow) var(--easing-decelerate) infinite; } .animate-wiggle { animation: wiggle var(--animation-duration-normal) var(--easing-smooth) infinite; } .animate-float { animation: float var(--animation-duration-slower) var(--easing-smooth) infinite; } .animate-shake { animation: shake var(--animation-duration-fast) var(--easing-smooth) var(--iteration-twice); } .animate-heartbeat { animation: heartbeat var(--animation-duration-slow) var(--easing-smooth) infinite; } .animate-elastic { animation: elastic var(--animation-duration-slow) var(--easing-decelerate) var(--iteration-once); } } /** * ========================================== * Experimentelles Feature: Animation Composition * ========================================== * * HINWEIS: Diese Funktion ist experimentell und hat derzeit eingeschränkte Browserunterstützung. * Nur in modernsten Browsern verwenden oder mit entsprechenden Fallbacks. * * animation-composition bestimmt, wie Animationen miteinander kombiniert werden: * - replace: Animation ersetzt bestehende Animationen (Standard) * - add: Animation wird zu bestehenden Animationen hinzugefügt * - accumulate: Animation wird zu bestehenden Animationen hinzugerechnet */ @layer animation-composition { /* Animation-Composition Utilities */ .composition-replace { animation-composition: replace; } .composition-add { animation-composition: add; } .composition-accumulate { animation-composition: accumulate; } /* Experimentelle Präsets mit composition */ .animate-combined-bounce { animation-composition: accumulate; animation-duration: var(--animation-duration-slow), var(--animation-duration-normal); animation-name: bounce, fade-in; } .animate-combined-shake { animation-composition: accumulate; animation-duration: var(--animation-duration-fast), var(--animation-duration-normal); animation-name: shake, fade-in; } /* Kombinierte Bewegungen mit accumulate */ .animate-path { animation: slide-in-right var(--animation-duration-slow) var(--easing-decelerate), slide-in-up var(--animation-duration-normal) var(--easing-decelerate) var(--delay-sm); animation-composition: accumulate; animation-fill-mode: both; } .animate-zoom-bounce { animation: scale-in var(--animation-duration-normal) var(--easing-decelerate), bounce var(--animation-duration-slow) var(--ease-bounce) var(--delay-sm); animation-composition: accumulate; animation-fill-mode: both; } } /** * ========================================== * Dialog-Animationen * ========================================== */ @layer dialog-animations { /* Dialog-Animationen für <dialog> Element und modale Fenster */ .dialog-animated { animation-duration: var(--dialog-duration); animation-fill-mode: both; animation-timing-function: var(--easing-decelerate); transform-origin: center top; will-change: transform, opacity; } /* Einblenden mit Scale und Slide */ .dialog-enter { animation-name: dialog-enter; } /* Ausblenden mit Scale und Slide */ .dialog-exit { animation-name: dialog-exit; } /* Backdrop-Animationen */ .dialog-backdrop-animated::backdrop { animation: fade-in var(--dialog-duration) var(--easing-decelerate); animation-fill-mode: both; background-color: rgb(0 0 0 / var(--dialog-backdrop-opacity)); will-change: opacity; } /* Direkte Anwendung auf <dialog>-Element */ dialog.animated { animation: dialog-enter var(--dialog-duration) var(--easing-decelerate); animation-fill-mode: both; will-change: transform, opacity; } dialog.animated::backdrop { animation: fade-in var(--dialog-duration) var(--easing-decelerate); animation-fill-mode: both; background-color: rgb(0 0 0 / var(--dialog-backdrop-opacity)); will-change: opacity; } dialog.animated[closing] { animation: dialog-exit var(--dialog-duration) var(--easing-smooth); will-change: transform, opacity; } dialog.animated[closing]::backdrop { animation: fade-out var(--dialog-duration) var(--easing-smooth); will-change: opacity; } } /** * ========================================== * Fokus-Animationen * ========================================== */ @layer focus-animations { /* Animierter Fokus-Ring für verbesserte Barrierefreiheit */ .focus-ring-animated { outline: none; position: relative; transition: box-shadow var(--animation-duration-normal) var(--easing-decelerate); } .focus-ring-animated:focus-visible { animation: focus-pulse var(--focus-animation-duration) var(--easing-decelerate) infinite; box-shadow: 0 0 0 var(--focus-ring-size) var(--focus-color); } /* Varianten für unterschiedliche Farben */ .focus-ring-animated.primary:focus-visible { --focus-color: var(--color-primary-500, rgb(66 153 225 / 60%)); } .focus-ring-animated.warning:focus-visible { --focus-color: var(--color-warning-500, rgb(237 137 54 / 0.6)); } .focus-ring-animated.error:focus-visible { --focus-color: var(--color-error-500, rgb(245 101 101 / 0.6)); } /* Verstärkter Fokus-Ring für Screenreader-Nutzer */ .sr-focus-style { display: none; } @media screen and (forced-colors: active) { .focus-ring-animated:focus-visible { animation: var(--animation-none); box-shadow: none; outline: var(--spacing-1) solid CanvasText; } .sr-focus-style { border: var(--spacing-1) solid CanvasText; display: block; height: calc(100 + var(--spacing-2-5)); left: calc(-1 * var(--spacing-1)); pointer-events: none; position: absolute; top: calc(-1 * var(--spacing-1)); width: calc(100 + var(--spacing-2-5)); z-index: var(--z-index-1); } } @media (prefers-contrast: more) { .focus-ring-animated { animation: var(--animation-none); outline: var(--border-width-thick) solid var(--focus-color, currentColor); } } } /** * ========================================== * Gestaffelte Animationen (Staggered) * ========================================== */ @layer staggered-animations { /* Container für gestaffelte Animationen */ .staggered-container > * { animation-fill-mode: both; opacity: var(--opacity-0); } /* Gestaffelte Einblendanimation */ .staggered-fade-in > * { animation-duration: var(--animation-duration-normal); animation-name: fade-in; animation-timing-function: var(--easing-decelerate); } /* Gestaffelte Slide-Up-Animation */ .staggered-slide-in-up > * { animation-duration: var(--animation-duration-normal); animation-name: slide-in-up; animation-timing-function: var(--easing-decelerate); } /* Gestaffelte Slide-Down-Animation */ .staggered-slide-in-down > * { animation-duration: var(--animation-duration-normal); animation-name: slide-in-down; animation-timing-function: var(--easing-decelerate); } /* Gestaffelte Slide-Left-Animation */ .staggered-slide-in-left > * { animation-duration: var(--animation-duration-normal); animation-name: slide-in-left; animation-timing-function: var(--easing-decelerate); } /* Gestaffelte Slide-Right-Animation */ .staggered-slide-in-right > * { animation-duration: var(--animation-duration-normal); animation-name: slide-in-right; animation-timing-function: var(--easing-decelerate); } /* Automatische Verzögerungen basierend auf nth-child */ .staggered-container > *:nth-child(1) { animation-delay: calc(var(--stagger-base-delay)); } .staggered-container > *:nth-child(2) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 1); } .staggered-container > *:nth-child(3) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 2); } .staggered-container > *:nth-child(4) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 3); } .staggered-container > *:nth-child(5) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 4); } .staggered-container > *:nth-child(6) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 5); } .staggered-container > *:nth-child(7) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 6); } .staggered-container > *:nth-child(8) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 7); } .staggered-container > *:nth-child(9) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 8); } .staggered-container > *:nth-child(10) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 9); } .staggered-container > *:nth-child(n+11) { animation-delay: min(calc(var(--stagger-base-delay) + var(--stagger-increment) * 10), var(--stagger-max-delay)); } /* Verzögerungsgruppen */ .stagger-group-1 > * { --stagger-base-delay: 0ms; } .stagger-group-2 > * { --stagger-base-delay: 100ms; } .stagger-group-3 > * { --stagger-base-delay: 200ms; } /* Verzögerungsinkremente */ .stagger-increment-small > * { --stagger-increment: 25ms; } .stagger-increment-normal > * { --stagger-increment: 50ms; } .stagger-increment-large > * { --stagger-increment: 100ms; } /* Richtung der Staffelung ändern (umkehren) */ .stagger-reverse { counter-reset: section; } .stagger-reverse > * { counter-increment: section; } .stagger-reverse > *:nth-child(1) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 9); } .stagger-reverse > *:nth-child(2) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 8); } .stagger-reverse > *:nth-child(3) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 7); } .stagger-reverse > *:nth-child(4) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 6); } .stagger-reverse > *:nth-child(5) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 5); } .stagger-reverse > *:nth-child(6) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 4); } .stagger-reverse > *:nth-child(7) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 3); } .stagger-reverse > *:nth-child(8) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 2); } .stagger-reverse > *:nth-child(9) { animation-delay: calc(var(--stagger-base-delay) + var(--stagger-increment) * 1); } .stagger-reverse > *:nth-child(10) { animation-delay: calc(var(--stagger-base-delay)); } } /** * ========================================== * Transition-Behavior Utilities * ========================================== * * Diese Utilities erlauben Übergänge zwischen normalerweise * nicht-interpolierbaren Eigenschaften (wie display, visibility, etc.) */ @layer transition-behavior { /* Erlaubt Übergänge zwischen diskreten Werten */ .transition-allow-discrete { transition-behavior: allow-discrete; } /* Anwendung auf spezifische Elemente/Eigenschaften */ .fade-discrete { transition-behavior: allow-discrete; transition-duration: var(--animation-duration-normal); transition-property: opacity, visibility; transition-timing-function: var(--easing-decelerate); } /* Element, das beim Ausblenden auch aus dem DOM-Fluss entfernt wird */ .fade-remove { transition-behavior: allow-discrete; transition-duration: var(--animation-duration-normal); transition-property: opacity, visibility, display; transition-timing-function: var(--easing-decelerate); } /* Erlaubt Übergang bei aria-hidden ohne Sprung/Ruckeln */ .transition-aria-state { transition-behavior: allow-discrete; transition-duration: var(--animation-duration-normal); transition-property: opacity, transform, aria-hidden; transition-timing-function: var(--easing-decelerate); } /* Anwendungsklasse für Visibility-Wechsel */ .animate-visibility { transition: opacity var(--animation-duration-normal) var(--easing-decelerate), visibility 0s linear var(--animation-duration-normal); transition-behavior: allow-discrete; } .animate-visibility.visible { opacity: var(--opacity-100); transition: opacity var(--animation-duration-normal) var(--easing-decelerate), visibility 0s linear 0s; visibility: visible; } .animate-visibility:not(.visible) { opacity: var(--opacity-0); visibility: hidden; } } /** * ========================================== * Backdrops (Overlays) * ========================================== * * Halbdurchsichtige Hintergrundebenen für Dialoge, Popover, etc. */ @layer backdrop { /* Basis-Backdrop mit Animation */ .backdrop { animation: fade-in var(--backdrop-animation-duration) var(--easing-decelerate) forwards; background-color: var(--backdrop-bg-color); inset: 0; pointer-events: auto; position: fixed; z-index: var(--z-index-backdrop, 1000); } /* Backdrop mit Unschärfe-Effekt */ .backdrop-blur { backdrop-filter: blur(var(--backdrop-blur, var(--spacing-1))); } /* Backdrop-Varianten */ .backdrop-light { --backdrop-opacity: var(--opacity-0).25; --backdrop-bg-color: rgb(255 255 255 / var(--backdrop-opacity)); } .backdrop-dark { --backdrop-opacity: var(--opacity-0).75; --backdrop-bg-color: rgb(0 0 0 / var(--backdrop-opacity)); } .backdrop-medium { --backdrop-opacity: var(--opacity-0).5; } .backdrop-strong { --backdrop-opacity: var(--opacity-0).85; } /* Backdrop mit transition-behavior für smootheren Exit */ .backdrop-transition { opacity: var(--opacity-100); transition: opacity var(--backdrop-animation-duration) var(--easing-decelerate), visibility 0s linear; transition-behavior: allow-discrete; visibility: visible; } .backdrop-transition.exit { opacity: var(--opacity-0); transition: opacity var(--backdrop-animation-duration) var(--ease-in), visibility 0s linear var(--backdrop-animation-duration); visibility: hidden; } /* Backdrop bei reduzierter Bewegung */ @media (prefers-reduced-motion: reduce) { .backdrop { animation: var(--animation-none); opacity: var(--opacity-100); } .backdrop-transition, .backdrop-transition.exit { transition: var(--transition-none); } } /* Backdrop bei erhöhtem Kontrast */ @media (prefers-contrast: more) { .backdrop, .backdrop-light, .backdrop-dark { --backdrop-opacity: var(--opacity-0).9; backdrop-filter: none; } } } /** * ========================================== * Flüssige Interpolation mit Keywords * ========================================== * * Diese Klassen verwenden CSS-Schlüsselwörter für Größen, die dank * 'interpolate-size: allow-keywords' flüssig interpoliert werden. */ @layer keyword-animations { /* Animation-Klasse mit flüssiger Interpolation zwischen Schlüsselwörtern */ .animate-keyword-size { /* flüssige Interpolation zwischen Schlüsselwörtern */ interpolate-size: allow-keywords; transition-duration: var(--animation-duration-normal); transition-property: font-size; transition-timing-function: var(--easing-decelerate); } /* Schlüsselwort-basierte Größenvarianten */ .keyword-size-xs { font-size: x-small; } .keyword-size-sm { font-size: small; } .keyword-size-md { font-size: medium; } .keyword-size-lg { font-size: large; } .keyword-size-xl { font-size: x-large; } /* Flüssige Animation, die zwischen Keywords basiert auf Hoverzustand interpoliert */ .hover-grow { font-size: medium; interpolate-size: allow-keywords; transition: font-size var(--animation-duration-normal) var(--easing-decelerate); } .hover-grow:hover { font-size: large; } /* Kombinierte Animation mit flüssiger Interpolation */ .animate-grow-fade { animation: grow-fade var(--animation-duration-slow) var(--easing-decelerate); interpolate-size: allow-keywords; } /* Keyframes mit Schlüsselwörtern */ @keyframes grow-fade { 0% { font-size: x-small; opacity: var(--opacity-0); } 100% { font-size: large; opacity: var(--opacity-100); } } } } /** * ========================================== * Animations-Kontexte * ========================================== * * Diese Klassen ermöglichen es, Animation-Parameter für einen Container und alle seine * Kindelemente zu überschreiben, ohne die globalen Werte zu ändern. */ @layer animation-contexts { /* Geschwindigkeits-Kontexte */ .animation-context-fastest { --animation-duration-fastest: 80ms; --animation-duration-fast: 120ms; --animation-duration-normal: 200ms; --animation-duration-slow: 350ms; --animation-duration-slower: 500ms; --animation-duration-slowest: 750ms; } .animation-context-fast { --animation-duration-fastest: 100ms; --animation-duration-fast: 150ms; --animation-duration-normal: 250ms; --animation-duration-slow: 400ms; --animation-duration-slower: 600ms; --animation-duration-slowest: 800ms; } .animation-context-slow { --animation-duration-fastest: 150ms; --animation-duration-fast: 250ms; --animation-duration-normal: 450ms; --animation-duration-slow: 700ms; --animation-duration-slower: 1000ms; --animation-duration-slowest: 1500ms; } /* Skalierungs-Kontexte */ .scale-context-xs { --scale-xs: 0.99; --scale-sm: 0.97; --scale-md: 0.95; --scale-lg: 1.03; --scale-xl: 1.05; } .scale-context-sm { --scale-xs: 0.98; --scale-sm: 0.95; --scale-md: 0.9; --scale-lg: 1.05; --scale-xl: 1.1; } .scale-context-md { --scale-xs: 0.96; --scale-sm: 0.92; --scale-md: 0.85; --scale-lg: 1.08; --scale-xl: 1.15; } .scale-context-lg { --scale-xs: 0.94; --scale-sm: 0.88; --scale-md: 0.8; --scale-lg: 1.12; --scale-xl: 1.2; } /* Bewegungs-Kontexte */ .move-context-small { --move-xs: var(--border-width-thick); --move-sm: var(--spacing-1); --move-md: var(--spacing-2); --move-lg: var(--spacing-4); --move-xl: calc(var(--spacing-2) + var(--spacing-1)); --slide-distance: var(--move-md); } .move-context-medium { --move-xs: var(--spacing-1); --move-sm: var(--spacing-2); --move-md: var(--spacing-4); --move-lg: calc(var(--spacing-2) + var(--spacing-1)); --move-xl: 36px; --slide-distance: var(--move-md); } .move-context-large { --move-xs: var(--spacing-2); --move-sm: var(--spacing-4); --move-md: var(--spacing-3)(--border-width-thick); --move-lg: var(--spacing-4)(--spacing-2); --move-xl: var(--spacing-6)(--spacing-1); --slide-distance: var(--move-md); } /* Verzögerungs-Kontexte */ .delay-context-short { --delay-xs: 25ms; --delay-sm: 50ms; --delay-md: 100ms; --delay-lg: 200ms; --delay-xl: 300ms; --stagger-base-delay: 30ms; --stagger-increment: 30ms; } .delay-context-medium { --delay-xs: 50ms; --delay-sm: 100ms; --delay-md: 200ms; --delay-lg: 300ms; --delay-xl: 500ms; --stagger-base-delay: 50ms; --stagger-increment: 50ms; } .delay-context-long { --delay-xs: 100ms; --delay-sm: 200ms; --delay-md: 400ms; --delay-lg: 600ms; --delay-xl: 800ms; --stagger-base-delay: 100ms; --stagger-increment: 100ms; } /* Animations-Präset-Kontexte */ .animation-context-energetic { --animation-duration-normal: 250ms; --move-md: calc(var(--spacing-2) + var(--spacing-1)); --scale-sm: 0.9; --scale-lg: 1.1; --easing-decelerate: cubic-bezier(0.11, 0.5, 0.24, 1); --ease-bounce: cubic-bezier(0.25, -0.25, 0.1, 1.3); --stagger-increment: 30ms; } .animation-context-subtle { --animation-duration-normal: 400ms; --move-md: var(--spacing-2); --scale-sm: 0.98; --scale-lg: 1.02; --easing-decelerate: cubic-bezier(0.22, 0.61, 0.36, 1); --easing-smooth: cubic-bezier(0.42, 0, 0.58, 1); --stagger-increment: 70ms; } .animation-context-playful { --animation-duration-normal: 350ms; --move-md: var(--spacing-5); --scale-sm: 0.85; --scale-lg: 1.15; --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55); --ease-spring: cubic-bezier(0.68, -0.6, 0.32, 1.6); --wiggle-angle: 4deg; --bounce-height: var(--percentage-35); --stagger-increment: 40ms; } /* Automatische Anwendung der Kontextparameter auf Kindelemente */ /* Geschwindigkeits-Kontexte auf Animationen */ :where(.animation-context-fastest *) { animation-duration: var(--animation-duration-normal); } :where(.animation-context-fast *) { animation-duration: var(--animation-duration-normal); } :where(.animation-context-slow *) { animation-duration: var(--animation-duration-normal); } /* Automatische Anwendung auf spezifische Animationstypen */ :where(.animation-context-fastest *).animate-fade-in, :where(.animation-context-fastest *).fade-in { animation-duration: var(--animation-duration-fast); } :where(.animation-context-fastest *).animate-slide-in-up, :where(.animation-context-fastest *).slide-in-up { animation-duration: var(--animation-duration-normal); } /* Skalierungs-Kontexte auf transform-basierte Animationen */ :where(.scale-context-xs *).scale-in, :where(.scale-context-xs *).scale-out { --scale-sm: var(--scale-sm); } :where(.scale-context-sm *).scale-in, :where(.scale-context-sm *).scale-out { --scale-sm: var(--scale-sm); } :where(.scale-context-md *).scale-in, :where(.scale-context-md *).scale-out { --scale-sm: var(--scale-sm); } :where(.scale-context-lg *).scale-in, :where(.scale-context-lg *).scale-out { --scale-sm: var(--scale-sm); } /* Bewegungs-Kontexte auf Slide-Animationen */ :where(.move-context-small *).slide-in-up, :where(.move-context-small *).slide-in-down, :where(.move-context-small *).slide-in-left, :where(.move-context-small *).slide-in-right { --slide-distance: var(--move-md); } :where(.move-context-medium *).slide-in-up, :where(.move-context-medium *).slide-in-down, :where(.move-context-medium *).slide-in-left, :where(.move-context-medium *).slide-in-right { --slide-distance: var(--move-md); } :where(.move-context-large *).slide-in-up, :where(.move-context-large *).slide-in-down, :where(.move-context-large *).slide-in-left, :where(.move-context-large *).slide-in-right { --slide-distance: var(--move-md); } /* Verzögerungs-Kontexte auf gestaffelte Animationen */ :where(.delay-context-short *).staggered-container > * { --stagger-increment: var(--stagger-increment); } :where(.delay-context-medium *).staggered-container > * { --stagger-increment: var(--stagger-increment); } :where(.delay-context-long *).staggered-container > * { --stagger-increment: var(--stagger-increment); } /* Animationspräsets automatisch auf alle Animationstypen anwenden */ :where(.animation-context-energetic *) { animation-duration: var(--animation-duration-normal); animation-timing-function: var(--easing-decelerate); } :where(.animation-context-subtle *) { animation-duration: var(--animation-duration-normal); animation-timing-function: var(--easing-decelerate); } :where(.animation-context-playful *) { animation-duration: var(--animation-duration-normal); animation-timing-function: var(--ease-bounce); } /* Spezifische Animationstypen in Präsets anpassen */ :where(.animation-context-playful *).animate-bounce, :where(.animation-context-playful *).bounce { --bounce-height: var(--bounce-height); } } /* Reduzierte Bewegung für alle Animation-Klassen */ @media (prefers-reduced-motion: reduce) { .animate, .fade-in, .fade-out, .slide-in-up, .slide-in-down, .slide-in-left, .slide-in-right, .scale-in, .scale-out, .scroll-fade-in, .scroll-slide-in-up, .scroll-slide-in-left, .scroll-slide-in-right, .animate-bounce, .animate-pulse, .animate-spin, .animate-ping, .animate-wiggle, .animate-float, .animate-shake, .animate-heartbeat, .animate-elastic, .interaction-scale, .hover-glow, .tap-feedback, .dialog-enter, .dialog-exit, .dialog-backdrop-animated, .focus-ring-animated, .staggered-container > *, .staggered-fade-in > *, .staggered-slide-in-up > *, .staggered-slide-in-down > *, .staggered-slide-in-left > *, .staggered-slide-in-right > *, .backdrop, .backdrop-transition { animation: var(--animation-none) !important; transition: var(--transition-none) !important; } } /* Erhöhter Kontrast für alle Animation-Klassen */ @media (prefers-contrast: more) { /* Grundlegende Änderungen für alle Elemente mit Animation */ .animate, .fade-in, .fade-out, .slide-in-up, .slide-in-down, .slide-in-left, .slide-in-right, .scale-in, .scale-out, .scroll-fade-in, .scroll-slide-in-up, .scroll-slide-in-left, .scroll-slide-in-right, .backdrop, .backdrop-transition { /* Vereinfachte Animationen beibehalten, aber mit erhöhtem Kontrast arbeiten */ --animation-duration-normal: 200ms; /* Schnellere Animationen */ --animation-duration-slow: 300ms; --backdrop-animation-duration: 150ms; animation-timing-function: linear; /* Vereinfachte Timing-Funktion */ } /* Komplexe Animationen deaktivieren oder vereinfachen */ .animate-bounce, .animate-pulse, .animate-spin, .animate-ping, .animate-wigg