UNPKG

scradar

Version:

CSS-first scroll interaction library with progress-based animations

445 lines (375 loc) 12.5 kB
/** * Scradar Predefined Animations * CSS-first approach with customizable CSS variables */ /* Animation CSS Variables - Can be overridden */ :root { --fade-distance: 30px; --scale-start: 0.8; --scale-amount: 0.1; --parallax-slow: -20px; --parallax-medium: -50px; --parallax-fast: -100px; --rotate-amount: 360deg; --tilt-amount: 5deg; --bounce-distance: -20px; --transition-duration: 0.6s; --transition-easing: ease; } /* Base scradar element properties for layout stability */ .scradar { /* Ensure stable layout during animations */ contain: layout style paint; /* Prevent layout shifts from transforms */ transform-style: preserve-3d; backface-visibility: hidden; } /* Progress type variables - defined on scradar elements */ .scradar { /* Priority order: peak > visibility > fill > cover > enter > exit */ --progress: var(--peak, var(--visibility, var(--fill, var(--cover, var(--enter, var(--exit, 0)))))); --progress-peak: var(--peak, 0); --progress-visibility: var(--visibility, 0); --progress-fill: var(--fill, 0); --progress-cover: var(--cover, 0); --progress-enter: var(--enter, 0); --progress-exit: var(--exit, 0); } /* ============================================================================= FADE ANIMATIONS ============================================================================= */ .scradar__fade-in { opacity: calc(var(--progress)); } .scradar__fade-in--up { opacity: calc(var(--progress)); transform: translateY(calc((1 - var(--progress)) * var(--fade-distance))); } .scradar__fade-in--down { opacity: calc(var(--progress)); transform: translateY(calc((1 - var(--progress)) * var(--fade-distance) * -1)); } .scradar__fade-in--left { opacity: calc(var(--progress)); transform: translateX(calc((1 - var(--progress)) * var(--fade-distance) * -1)); } .scradar__fade-in--right { opacity: calc(var(--progress)); transform: translateX(calc((1 - var(--progress)) * var(--fade-distance))); } /* ============================================================================= SCALE ANIMATIONS ============================================================================= */ .scradar__scale-in { opacity: calc(var(--progress)); transform: scale(calc(var(--scale-start) + var(--progress) * (1 - var(--scale-start)))); } .scradar__scale-up { transform: scale(calc(1 + var(--progress) * var(--scale-amount))); } /* ============================================================================= PARALLAX ANIMATIONS ============================================================================= */ .scradar__parallax--slow { transform: translateY(calc(var(--progress) * var(--parallax-slow))); } .scradar__parallax--medium { transform: translateY(calc(var(--progress) * var(--parallax-medium))); } .scradar__parallax--fast { transform: translateY(calc(var(--progress) * var(--parallax-fast))); } /* ============================================================================= FILL-BASED ANIMATIONS ============================================================================= */ .scradar__progress-bar { position: relative; overflow: hidden; } .scradar__progress-bar::after { content: ''; position: absolute; top: 0; left: 0; height: 100%; width: calc(var(--progress) * 100%); background: currentColor; } .scradar__slide-reveal { clip-path: inset(0 calc(100% - var(--progress) * 100%) 0 0); } /* ============================================================================= TEXT ANIMATIONS ============================================================================= */ .scradar__text-reveal { background: linear-gradient(90deg, currentColor calc(var(--progress) * 100% - 15px), transparent calc(var(--progress) * 100% + 15px), transparent 100% ); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .scradar__typewriter { overflow: hidden; white-space: nowrap; border-right: 2px solid currentColor; width: calc(var(--progress) * 100%); } /* ============================================================================= STAGGER ANIMATIONS ============================================================================= */ .scradar__stagger--fade-in .scradar__stagger-item { opacity: 0; transform: translateY(20px); transition: opacity var(--transition-duration) var(--transition-easing), transform var(--transition-duration) var(--transition-easing); } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(1) { opacity: 1; transform: translateY(0); transition-delay: 0.1s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(2) { opacity: 1; transform: translateY(0); transition-delay: 0.2s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(3) { opacity: 1; transform: translateY(0); transition-delay: 0.3s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(4) { opacity: 1; transform: translateY(0); transition-delay: 0.4s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(5) { opacity: 1; transform: translateY(0); transition-delay: 0.5s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(6) { opacity: 1; transform: translateY(0); transition-delay: 0.6s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(7) { opacity: 1; transform: translateY(0); transition-delay: 0.7s; } .scradar__stagger--fade-in[data-scradar-in="1"] .scradar__stagger-item:nth-child(8) { opacity: 1; transform: translateY(0); transition-delay: 0.8s; } /* ============================================================================= ROTATION ANIMATIONS ============================================================================= */ .scradar__rotate { transform: rotate(calc(var(--progress) * var(--rotate-amount))); /* Ensure rotation doesn't affect layout calculations */ transform-origin: center center; /* Preserve original dimensions during rotation */ width: fit-content; height: fit-content; /* Prevent layout shifts */ contain: layout style paint; } .scradar__tilt { transform: rotate(calc(var(--progress) * var(--tilt-amount) - var(--tilt-amount) / 2)); /* Ensure rotation doesn't affect layout calculations */ transform-origin: center center; /* Preserve original dimensions during rotation */ width: fit-content; height: fit-content; /* Prevent layout shifts */ contain: layout style paint; } /* ============================================================================= FILTER ANIMATIONS ============================================================================= */ .scradar__color-shift { filter: hue-rotate(calc(var(--progress) * 180deg)); } .scradar__blur-in { filter: blur(calc((1 - var(--progress)) * 10px)); } /* ============================================================================= PEAK-BASED ANIMATIONS (rise and fall) ============================================================================= */ .scradar__bounce { transform: translateY(calc(var(--progress) * var(--bounce-distance))); } .scradar__pulse { transform: scale(calc(1 + var(--progress) * var(--scale-amount))); opacity: calc(0.7 + var(--progress) * 0.3); } .scradar__glow { box-shadow: 0 0 calc(var(--progress) * 20px) calc(var(--progress) * 10px) rgba(79, 195, 247, calc(var(--progress) * 0.3)); } /* ============================================================================= COMBINATION ANIMATIONS ============================================================================= */ .scradar__zoom-fade { opacity: calc(var(--progress)); transform: scale(calc(var(--scale-start) + var(--progress) * (1 - var(--scale-start)))) translateY(calc((1 - var(--progress)) * var(--fade-distance))); } .scradar__slide-scale { transform: translateX(calc((1 - var(--progress)) * var(--fade-distance))) scale(calc(var(--scale-start) + var(--progress) * (1 - var(--scale-start)))); } /* ============================================================================= TRIGGER-BASED ANIMATIONS (data-scradar-in attribute) ============================================================================= */ /* Trigger animations - when data-scradar-in="1" is set */ .scradar__trigger-fade-in[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-fade-in { opacity: 1; animation: scradar-fade-in var(--transition-duration) var(--transition-easing) forwards; } .scradar__trigger-fade-in--up[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-fade-in--up { opacity: 1; transform: translateY(0); animation: scradar-fade-in-up var(--transition-duration) var(--transition-easing) forwards; } .scradar__trigger-scale-in[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-scale-in { opacity: 1; transform: scale(1); animation: scradar-scale-in var(--transition-duration) var(--transition-easing) forwards; } .scradar__trigger-bounce[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-bounce { animation: scradar-bounce var(--transition-duration) var(--transition-easing) forwards; } .scradar__trigger-pulse[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-pulse { animation: scradar-pulse var(--transition-duration) var(--transition-easing) forwards; } .scradar__trigger-glow[data-scradar-in="1"], .scradar[data-scradar-in="1"] .scradar__trigger-glow { animation: scradar-glow var(--transition-duration) var(--transition-easing) forwards; } /* Keyframe animations for trigger-based effects */ @keyframes scradar-fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes scradar-fade-in-up { from { opacity: 0; transform: translateY(var(--fade-distance)); } to { opacity: 1; transform: translateY(0); } } @keyframes scradar-scale-in { from { opacity: 0; transform: scale(var(--scale-start)); } to { opacity: 1; transform: scale(1); } } @keyframes scradar-bounce { 0%, 20%, 53%, 80%, 100% { transform: translateY(0); } 40%, 43% { transform: translateY(var(--bounce-distance)); } 70% { transform: translateY(calc(var(--bounce-distance) * 0.6)); } 90% { transform: translateY(calc(var(--bounce-distance) * 0.3)); } } @keyframes scradar-pulse { 0% { transform: scale(1); opacity: 0.7; } 50% { transform: scale(calc(1 + var(--scale-amount))); opacity: 1; } 100% { transform: scale(1); opacity: 0.7; } } @keyframes scradar-glow { 0% { box-shadow: 0 0 0 0 rgba(79, 195, 247, 0.3); } 50% { box-shadow: 0 0 20px 10px rgba(79, 195, 247, 0.3); } 100% { box-shadow: 0 0 0 0 rgba(79, 195, 247, 0.3); } } /* ============================================================================= PROGRESS TYPE MODIFIERS ============================================================================= */ /* Use different progress types */ .scradar__use-visibility { --progress: var(--progress-visibility); } .scradar__use-fill { --progress: var(--progress-fill); } .scradar__use-peak { --progress: var(--progress-peak); } .scradar__use-cover { --progress: var(--progress-cover); } .scradar__use-enter { --progress: var(--progress-enter); } .scradar__use-exit { --progress: var(--progress-exit); } /* ============================================================================= UTILITY CLASSES ============================================================================= */ /* Custom timing functions */ .scradar__ease-out-back { --transition-easing: cubic-bezier(0.34, 1.56, 0.64, 1); } .scradar__ease-out-elastic { --transition-easing: cubic-bezier(0.68, -0.55, 0.265, 1.55); } .scradar__ease-out-bounce { --transition-easing: cubic-bezier(0.68, -0.6, 0.32, 1.6); } /* Duration modifiers */ .scradar__fast { --transition-duration: 0.3s; } .scradar__slow { --transition-duration: 1.2s; } .scradar__very-slow { --transition-duration: 2s; } /* Distance modifiers */ .scradar__small-distance { --fade-distance: 15px; } .scradar__large-distance { --fade-distance: 60px; } .scradar__huge-distance { --fade-distance: 100px; }