/** * AKSRT Animations — animate.css 等价(独立重写) * ------------------------------------------------------------ * 关键帧 + 工具类 + IntersectionObserver 触发配合 * 触发 JS 已在 enhancements2.js([data-aksrt-animate] 属性) * 本文件仅定义 @keyframes 和 .aksrt-anim-* 工具类 */ /* ============================================================ * Keyframes * ============================================================ */ /* Fade 系列 */ @keyframes aksrtFadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes aksrtFadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } } @keyframes aksrtFadeInDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: none; } } @keyframes aksrtFadeInLeft { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: none; } } @keyframes aksrtFadeInRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: none; } } /* Zoom 系列 */ @keyframes aksrtZoomIn { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: none; } } @keyframes aksrtZoomInUp { from { opacity: 0; transform: scale(.85) translateY(20px); } to { opacity: 1; transform: none; } } /* Bounce 系列 */ @keyframes aksrtBounceIn { 0% { opacity: 0; transform: scale(.3); } 50% { opacity: 1; transform: scale(1.08); } 70% { transform: scale(.95); } 100% { opacity: 1; transform: none; } } @keyframes aksrtBounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-12px); } 60% { transform: translateY(-6px); } } /* Pulse */ @keyframes aksrtPulse { 0% { transform: scale(1); } 50% { transform: scale(1.06); } 100% { transform: scale(1); } } /* Flash */ @keyframes aksrtFlash { 0%, 50%, 100% { opacity: 1; } 25%, 75% { opacity: 0; } } /* RubberBand */ @keyframes aksrtRubberBand { 0% { transform: scale(1); } 30% { transform: scaleX(1.25) scaleY(0.75); } 40% { transform: scaleX(0.75) scaleY(1.25); } 50% { transform: scaleX(1.15) scaleY(0.85); } 65% { transform: scaleX(0.95) scaleY(1.05); } 75% { transform: scaleX(1.05) scaleY(0.95); } 100% { transform: scale(1); } } /* Shake */ @keyframes aksrtShake { 0%, 100% { transform: translateX(0); } 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); } 20%, 40%, 60%, 80% { transform: translateX(4px); } } /* Swing */ @keyframes aksrtSwing { 20% { transform: rotate(15deg); } 40% { transform: rotate(-10deg); } 60% { transform: rotate(5deg); } 80% { transform: rotate(-5deg); } 100% { transform: none; } } /* Tada */ @keyframes aksrtTada { 0% { transform: scale(1); } 10%, 20% { transform: scale(0.9) rotate(-3deg); } 30%, 50%, 70%, 90% { transform: scale(1.1) rotate(3deg); } 40%, 60%, 80% { transform: scale(1.1) rotate(-3deg); } 100% { transform: scale(1) rotate(0); } } /* Wobble */ @keyframes aksrtWobble { 0% { transform: none; } 15% { transform: translateX(-25%) rotate(-5deg); } 30% { transform: translateX(20%) rotate(3deg); } 45% { transform: translateX(-15%) rotate(-3deg); } 60% { transform: translateX(10%) rotate(2deg); } 75% { transform: translateX(-5%) rotate(-1deg); } 100% { transform: none; } } /* Slide 系列 */ @keyframes aksrtSlideInUp { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: none; } } @keyframes aksrtSlideInDown { from { opacity: 0; transform: translateY(-100%); } to { opacity: 1; transform: none; } } @keyframes aksrtSlideInLeft { from { opacity: 0; transform: translateX(-100%); } to { opacity: 1; transform: none; } } @keyframes aksrtSlideInRight { from { opacity: 0; transform: translateX(100%); } to { opacity: 1; transform: none; } } /* HeartBeat */ @keyframes aksrtHeartBeat { 0% { transform: scale(1); } 14% { transform: scale(1.3); } 28% { transform: scale(1); } 42% { transform: scale(1.3); } 70% { transform: scale(1); } 100% { transform: scale(1); } } /* Jello */ @keyframes aksrtJello { 0%, 100% { transform: none; } 11% { transform: skewX(-12.5deg) skewY(-12.5deg); } 22% { transform: skewX(6.25deg) skewY(6.25deg); } 33% { transform: skewX(-6.25deg) skewY(-6.25deg); } 44% { transform: skewX(3.125deg) skewY(3.125deg); } 55% { transform: skewX(-3.125deg) skewY(-3.125deg); } 66% { transform: skewX(1.5625deg) skewY(1.5625deg); } 77% { transform: skewX(-1.5625deg) skewY(-1.5625deg); } 88% { transform: skewX(0.78125deg) skewY(0.78125deg); } } /* HeadShake */ @keyframes aksrtHeadShake { 0% { transform: translateX(0); } 6.5% { transform: translateX(-6px) rotateY(-9deg); } 18.5% { transform: translateX(5px) rotateY(7deg); } 31.5% { transform: translateX(-3px) rotateY(-5deg); } 43.5% { transform: translateX(2px) rotateY(3deg); } 50% { transform: translateX(0); } 100% { transform: translateX(0); } } /* BounceOut — 退出动画 */ @keyframes aksrtBounceOut { 0% { transform: scale(1); } 25% { transform: scale(0.95); } 50% { transform: scale(1.1); } 75% { transform: scale(0.97); } 100% { transform: scale(1); opacity: 0; } } /* ZoomOut — 退出动画 */ @keyframes aksrtZoomOut { 0% { opacity: 1; transform: none; } 100% { opacity: 0; transform: scale(0.85); } } /* BackIn/BackOut */ @keyframes aksrtBackInUp { 0% { opacity: 0; transform: translateY(30px) scale(0.7); } 80% { opacity: 0.8; transform: translateY(-5px) scale(1.02); } 100% { opacity: 1; transform: none; } } @keyframes aksrtBackInDown { 0% { opacity: 0; transform: translateY(-30px) scale(0.7); } 80% { opacity: 0.8; transform: translateY(5px) scale(1.02); } 100% { opacity: 1; transform: none; } } /* Flip */ @keyframes aksrtFlip { 0% { transform: perspective(400px) rotateY(90deg); opacity: 0; } 40% { transform: perspective(400px) rotateY(-10deg); } 70% { transform: perspective(400px) rotateY(10deg); } 100% { transform: perspective(400px) rotateY(0deg); opacity: 1; } } @keyframes aksrtFlipInX { 0% { transform: perspective(400px) rotateX(90deg); opacity: 0; } 40% { transform: perspective(400px) rotateX(-10deg); } 70% { transform: perspective(400px) rotateX(10deg); } 100% { transform: perspective(400px) rotateX(0deg); opacity: 1; } } /* ============================================================ * Animation utility classes * ============================================================ */ .aksrt-anim-fade-in { animation: aksrtFadeIn var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-fade-up { animation: aksrtFadeInUp var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-fade-down { animation: aksrtFadeInDown var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-fade-left { animation: aksrtFadeInLeft var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-fade-right { animation: aksrtFadeInRight var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-zoom-in { animation: aksrtZoomIn var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-zoom-in-up { animation: aksrtZoomInUp var(--dur-base, .4s) var(--ease-out, ease) both; } .aksrt-anim-bounce-in { animation: aksrtBounceIn .6s var(--ease-out, ease) both; } .aksrt-anim-bounce { animation: aksrtBounce 1s ease both; } .aksrt-anim-pulse { animation: aksrtPulse 1s ease infinite; } .aksrt-anim-flash { animation: aksrtFlash 1s ease both; } .aksrt-anim-rubber-band { animation: aksrtRubberBand .8s ease both; } .aksrt-anim-shake { animation: aksrtShake .5s ease both; } .aksrt-anim-swing { animation: aksrtSwing .6s var(--ease-out, ease) both; } .aksrt-anim-tada { animation: aksrtTada 1s ease both; } .aksrt-anim-wobble { animation: aksrtWobble .8s ease both; } .aksrt-anim-heart-beat { animation: aksrtHeartBeat 1.3s ease both; } .aksrt-anim-jello { animation: aksrtJello .8s ease both; } .aksrt-anim-head-shake { animation: aksrtHeadShake .8s ease both; } /* 退出动画 */ .aksrt-anim-bounce-out { animation: aksrtBounceOut .5s ease both; } .aksrt-anim-zoom-out { animation: aksrtZoomOut .3s ease both; } /* BackIn 动画 */ .aksrt-anim-back-in-up { animation: aksrtBackInUp .5s var(--ease-out, ease) both; } .aksrt-anim-back-in-down { animation: aksrtBackInDown .5s var(--ease-out, ease) both; } .aksrt-anim-slide-up { animation: aksrtSlideInUp .5s var(--ease-out, ease) both; } .aksrt-anim-slide-down { animation: aksrtSlideInDown .5s var(--ease-out, ease) both; } .aksrt-anim-slide-left { animation: aksrtSlideInLeft .5s var(--ease-out, ease) both; } .aksrt-anim-slide-right { animation: aksrtSlideInRight .5s var(--ease-out, ease) both; } .aksrt-anim-flip { animation: aksrtFlip .6s var(--ease-out, ease) both; } .aksrt-anim-flip-x { animation: aksrtFlipInX .6s var(--ease-out, ease) both; } /* ============================================================ * Duration modifiers * ============================================================ */ .aksrt-anim-fast { --dur-base: .2s; } .aksrt-anim-slow { --dur-base: .6s; } /* ============================================================ * Delay modifiers (配合 data-aksrt-delay 使用时为 inline, * 也可用 class 方式独立设置) * ============================================================ */ .aksrt-anim-delay-1 { animation-delay: .1s; } .aksrt-anim-delay-2 { animation-delay: .2s; } .aksrt-anim-delay-3 { animation-delay: .3s; } .aksrt-anim-delay-4 { animation-delay: .4s; } .aksrt-anim-delay-5 { animation-delay: .5s; } .aksrt-anim-delay-6 { animation-delay: .6s; } .aksrt-anim-delay-7 { animation-delay: .7s; } .aksrt-anim-delay-8 { animation-delay: .8s; } /* ============================================================ * Infinite modifier * ============================================================ */ .aksrt-anim-infinite { animation-iteration-count: infinite; } /* ============================================================ * Reduced-motion — 尊重用户偏好 * ============================================================ */ @media (prefers-reduced-motion: reduce) { .aksrt-anim-fade-in, .aksrt-anim-fade-up, .aksrt-anim-fade-down, .aksrt-anim-fade-left, .aksrt-anim-fade-right, .aksrt-anim-zoom-in, .aksrt-anim-zoom-in-up, .aksrt-anim-bounce-in, .aksrt-anim-bounce, .aksrt-anim-pulse, .aksrt-anim-flash, .aksrt-anim-rubber-band, .aksrt-anim-shake, .aksrt-anim-swing, .aksrt-anim-tada, .aksrt-anim-wobble, .aksrt-anim-heart-beat, .aksrt-anim-jello, .aksrt-anim-head-shake, .aksrt-anim-bounce-out, .aksrt-anim-zoom-out, .aksrt-anim-back-in-up, .aksrt-anim-back-in-down, .aksrt-anim-slide-up, .aksrt-anim-slide-down, .aksrt-anim-slide-left, .aksrt-anim-slide-right, .aksrt-anim-flip, .aksrt-anim-flip-x { animation: none !important; } }