@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
CSS
/**
* 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