/* 动画样式文件 */ /* 淡入动画 */ @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeInUp { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeInDown { from { opacity: 0; transform: translateY(-40px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeInLeft { from { opacity: 0; transform: translateX(-40px); } to { opacity: 1; transform: translateX(0); } } @keyframes fadeInRight { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } } /* 缩放动画 */ @keyframes scaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } @keyframes scaleOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } } /* 旋转动画 */ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes spinReverse { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } } /* 脉动动画 */ @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.8; transform: scale(1.05); } } @keyframes pulseSoft { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.02); } } /* 滑动动画 */ @keyframes slideInUp { from { transform: translateY(100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes slideInDown { from { transform: translateY(-100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes slideInLeft { from { transform: translateX(-100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideInRight { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } /* 弹跳动画 */ @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-20px); } 60% { transform: translateY(-10px); } } /* 闪烁动画 */ @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* 波浪动画 */ @keyframes wave { 0% { transform: translateX(0); } 50% { transform: translateX(-10px); } 100% { transform: translateX(0); } } /* 动画工具类 */ .animate-fade-in { animation: fadeIn var(--transition-normal); } .animate-fade-in-up { animation: fadeInUp var(--transition-normal); } .animate-fade-in-down { animation: fadeInDown var(--transition-normal); } .animate-fade-in-left { animation: fadeInLeft var(--transition-normal); } .animate-fade-in-right { animation: fadeInRight var(--transition-normal); } .animate-scale-in { animation: scaleIn var(--transition-normal); } .animate-scale-out { animation: scaleOut var(--transition-normal); } .animate-spin { animation: spin 1s linear infinite; } .animate-spin-reverse { animation: spinReverse 1s linear infinite; } .animate-pulse { animation: pulse 2s ease-in-out infinite; } .animate-pulse-soft { animation: pulseSoft 3s ease-in-out infinite; } .animate-slide-in-up { animation: slideInUp var(--transition-normal); } .animate-slide-in-down { animation: slideInDown var(--transition-normal); } .animate-slide-in-left { animation: slideInLeft var(--transition-normal); } .animate-slide-in-right { animation: slideInRight var(--transition-normal); } .animate-bounce { animation: bounce 2s infinite; } .animate-blink { animation: blink 1s infinite; } .animate-wave { animation: wave 2s ease-in-out infinite; } /* 延迟动画 */ .delay-100 { animation-delay: 100ms; } .delay-200 { animation-delay: 200ms; } .delay-300 { animation-delay: 300ms; } .delay-400 { animation-delay: 400ms; } .delay-500 { animation-delay: 500ms; } .delay-600 { animation-delay: 600ms; } .delay-700 { animation-delay: 700ms; } .delay-800 { animation-delay: 800ms; } .delay-900 { animation-delay: 900ms; } .delay-1000 { animation-delay: 1000ms; } /* 动画持续时间 */ .duration-fast { animation-duration: var(--transition-fast); } .duration-normal { animation-duration: var(--transition-normal); } .duration-slow { animation-duration: var(--transition-slow); } /* 页面切换动画 */ .page-transition { animation: fadeIn var(--transition-normal); } .page-transition.active { animation: fadeOut var(--transition-normal); } /* 悬停动画 */ .hover-lift { transition: transform var(--transition-normal); } .hover-lift:hover { transform: translateY(-4px); } .hover-scale { transition: transform var(--transition-normal); } .hover-scale:hover { transform: scale(1.05); } .hover-rotate { transition: transform var(--transition-normal); } .hover-rotate:hover { transform: rotate(5deg); } /* 加载动画 */ .loading-spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--primary-color); border-radius: 50%; animation: spin 1s linear infinite; } .loading-dots { display: flex; gap: 4px; } .loading-dots span { width: 8px; height: 8px; background-color: var(--primary-color); border-radius: 50%; animation: pulse 1.4s ease-in-out infinite; } .loading-dots span:nth-child(2) { animation-delay: 0.2s; } .loading-dots span:nth-child(3) { animation-delay: 0.4s; } /* 进度条动画 */ @keyframes progress { from { width: 0%; } to { width: 100%; } } .progress-bar { animation: progress 2s ease-in-out infinite; } /* 打字机效果 */ @keyframes typing { from { width: 0; } to { width: 100%; } } @keyframes blink-caret { from, to { border-color: transparent; } 50% { border-color: var(--primary-color); } } .typewriter { overflow: hidden; border-right: 2px solid var(--primary-color); white-space: nowrap; animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite; } /* 加载动画样式 */ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--bg-primary); display: flex; align-items: center; justify-content: center; z-index: 9999; transition: opacity 0.5s ease, visibility 0.5s ease; } .loading-overlay.hidden { opacity: 0; visibility: hidden; } .loading-spinner { text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; } .spinner { width: 60px; height: 60px; border: 4px solid rgba(30, 111, 187, 0.1); border-top-color: var(--primary-color); border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 20px; } .loading-text { color: var(--text-secondary); font-size: var(--font-size-lg); font-weight: 500; text-align: center; animation: none !important; /* 确保文字不应用任何动画 */ } /* 骨架屏加载动画 */ .skeleton { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: skeleton-loading 1.5s infinite; border-radius: var(--radius-md); } @keyframes skeleton-loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } /* 渐进式加载动画 */ .fade-in-load { opacity: 0; transform: translateY(20px); animation: fadeInUp 0.6s ease forwards; } .fade-in-load.delay-1 { animation-delay: 0.1s; } .fade-in-load.delay-2 { animation-delay: 0.2s; } .fade-in-load.delay-3 { animation-delay: 0.3s; } .fade-in-load.delay-4 { animation-delay: 0.4s; } /* 性能优化:减少重绘 */ .will-change-transform { will-change: transform; } .will-change-opacity { will-change: opacity; } /* 图片懒加载占位符 */ .lazy-image { background-color: var(--bg-secondary); position: relative; overflow: hidden; } .lazy-image::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }