本文档整理了10+个顶级网站(Stripe、Linear、Apple、Airbnb、OpenClaw、Awwwards、Notion、Figma、Vercel、Spotify)的动效设计特点,并推导出每种效果的技术实现路径。
- 滚动触发动画 (Scroll-triggered)
- 数字滚动动画 (Count-up Animation)
- 视差滚动 (Parallax Scrolling)
- 模糊效果动画 (Blur/Glassmorphism)
- 页面过渡转场 (Page Transitions)
- 悬停微交互 (Hover Micro-interactions)
- 粒子效果 (Particle Effects)
- 渐变动画 (Gradient Animation)
- 文字动画 (Text Animations)
- 3D 变换与交互 (3D Transforms)
- 主流动效工具栈
- 设计趋势总结
- 性能优化 (Performance Optimization)
- 无障碍设计 (Accessibility / A11y)
- 浏览器兼容性 (Browser Compatibility)
- 调试工具 (Debugging Tools)
- 实践案例:从简单到高级的动画升级路径
实现效果:元素随着滚动进入视口时产生动画
- Awwwards 获奖网站
- Stripe 首页产品展示
| 技术 | 说明 | 推荐度 |
|---|---|---|
| Intersection Observer API | 监听元素是否进入视口,现代浏览器原生支持 | ⭐⭐⭐⭐⭐ |
| GSAP ScrollTrigger | 最流行的滚动动画库,功能强大 | ⭐⭐⭐⭐⭐ |
| Framer Motion | React 生态的动画库,支持滚动触发 | ⭐⭐⭐⭐ |
| CSS scroll() | 新兴 CSS 原生支持(兼容性待提升) | ⭐⭐⭐ |
// 使用 Intersection Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
}
});
}, { threshold: 0.1 });
// 观察所有需要动画的元素
document.querySelectorAll('.scroll-animate').forEach(el => {
observer.observe(el);
});/* CSS 动画定义 */
.scroll-animate {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.scroll-animate.animate-in {
opacity: 1;
transform: translateY(0);
}实现效果:数字从 0 增长到最终值
- Stripe 首页统计数据($1.9T 交易量、135+ 货币种类)
| 技术 | 说明 | 推荐度 |
|---|---|---|
| requestAnimationFrame | 逐帧更新数字,性能最流畅 | ⭐⭐⭐⭐⭐ |
| CountUp.js | 专门处理数字滚动的轻量库 | ⭐⭐⭐⭐⭐ |
| GSAP | 功能全面的动画库内置数字动画 | ⭐⭐⭐⭐⭐ |
| CSS counter | 仅适用简单场景 | ⭐⭐ |
// 使用 requestAnimationFrame 实现流畅的数字滚动
function animateValue(element, start, end, duration) {
const range = end - start;
let current = start;
const startTime = performance.now();
function update(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// 使用缓动函数让动画更自然
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
current = start + (range * easeOutQuart);
element.textContent = Math.floor(current).toLocaleString();
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
// 使用示例
animateValue(document.getElementById('counter'), 0, 100, 2000);// 使用 CountUp.js(更简单)
import CountUp from 'countup.js';
const counter = new CountUp('counter', 100, {
duration: 2,
separator: ',',
prefix: '$'
});
if (!counter.error) {
counter.start();
}实现效果:背景移动速度与前景不同,产生深度感
- Apple 产品页面
- Awwwards 创意网站
| 技术 | 说明 | 推荐度 |
|---|---|---|
| CSS transform: translateZ() | 利用 CSS 3D 变换实现硬件加速 | ⭐⭐⭐⭐⭐ |
| GSAP ScrollTrigger + parallax | 配合滚动库实现复杂视差 | ⭐⭐⭐⭐⭐ |
| Rellax.js | 轻量级视差库 | ⭐⭐⭐⭐ |
| Locomotive Scroll | 带惯性的平滑滚动库 | ⭐⭐⭐⭐ |
/* 基础视差 CSS - 利用 3D 变换 */
.parallax-container {
perspective: 1px;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}
.parallax-layer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.parallax-back {
transform: translateZ(-1px) scale(2);
/* 背景在更远的Z轴,滚动时移动更慢 */
}
.parallax-front {
transform: translateZ(0);
/* 前景正常滚动 */
}// GSAP ScrollTrigger 实现视差
gsap.to('.parallax-bg', {
scrollTrigger: {
trigger: '.parallax-section',
scrub: true
},
y: -100, // 背景移动距离
ease: 'none'
});实现效果:毛玻璃、背景模糊效果
- Linear 项目管理工具
- macOS 系统风格网页
| 技术 | 说明 | 推荐度 |
|---|---|---|
| CSS backdrop-filter: blur() | 现代浏览器原生支持 | ⭐⭐⭐⭐⭐ |
| SVG filter | 可创建更复杂的模糊效果 | ⭐⭐⭐⭐ |
| Canvas 模糊 | 适合动态模糊处理 | ⭐⭐⭐ |
/* 毛玻璃效果 - 现代浏览器 */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
}
/* 深色毛玻璃 */
.glass-dark {
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
}/* 动态模糊动画 */
@keyframes blur-pulse {
0%, 100% { filter: blur(0); }
50% { filter: blur(10px); }
}
.blur-animate {
animation: blur-pulse 2s ease-in-out infinite;
}实现效果:页面切换时平滑过渡,非直接刷新
- Notion 文档页面
- Vercel 文档
| 技术 | 说明 | 推荐度 |
|---|---|---|
| Barba.js | 最流行的页面过渡库 | ⭐⭐⭐⭐⭐ |
| GSAP + Flip | 动画化布局变化 | ⭐⭐⭐⭐⭐ |
| View Transitions API | 浏览器原生支持(新技术) | ⭐⭐⭐⭐ |
| Framer Motion (AnimatePresence) | React 组件过渡 | ⭐⭐⭐⭐ |
// Barba.js 基础用法
import barba from '@barba/core';
barba.init({
transitions: [{
name: 'opacity-transition',
leave(data) {
return gsap.to(data.current.container, {
opacity: 0,
duration: 0.3
});
},
enter(data) {
return gsap.from(data.next.container, {
opacity: 0,
duration: 0.3
});
}
}]
});// View Transitions API - 现代浏览器原生支持
document.addEventListener('click', async (e) => {
if (e.target.matches('a')) {
e.preventDefault();
const response = await fetch(e.target.href);
const html = await response.text();
document.startViewTransition(() => {
document.body.innerHTML = html;
});
}
});实现效果:按钮、卡片悬停时的细微动画
- Stripe 按钮交互
- Figma 界面元素
| 技术 | 说明 | 推荐度 |
|---|---|---|
| CSS :hover + transitions | 基础但足够用 | ⭐⭐⭐⭐⭐ |
| GSAP hover | 可控性更强 | ⭐⭐⭐⭐⭐ |
| Motion One | 轻量级 Web Animation API 封装 | ⭐⭐⭐⭐ |
/* 卡片悬停上浮 + 阴影 */
.card {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
/* 按钮悬停效果 */
.btn {
position: relative;
overflow: hidden;
transition: background-color 0.3s ease;
}
.btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:hover::after {
width: 300px;
height: 300px;
}// GSAP 悬停动画 - 更加精细的控制
card.addEventListener('mouseenter', () => {
gsap.to(card, {
scale: 1.05,
duration: 0.3,
ease: 'power2.out'
});
});
card.addEventListener('mouseleave', () => {
gsap.to(card, {
scale: 1,
duration: 0.3,
ease: 'power2.in'
});
});实现效果:背景粒子浮动、飘落
- Vercel 首页
- Awwwards 创意展示页
| 技术 | 说明 | 推荐度 |
|---|---|---|
| Canvas API | 底层绘制,性能好 | ⭐⭐⭐⭐⭐ |
| PixiJS | 2D WebGL 渲染,速度最快 | ⭐⭐⭐⭐⭐ |
| Three.js | 3D 粒子(需要 3D 效果时) | ⭐⭐⭐⭐⭐ |
| tsParticles | 现成粒子组件库 | ⭐⭐⭐⭐ |
// Canvas 粒子系统基础实现
class Particle {
constructor(canvas) {
this.canvas = canvas;
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = (Math.random() - 0.5) * 0.5;
this.vy = (Math.random() - 0.5) * 0.5;
this.size = Math.random() * 2 + 1;
this.color = `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.1})`;
}
update() {
this.x += this.vx;
this.y += this.vy;
// 边界检测
if (this.x < 0 || this.x > this.canvas.width) this.vx *= -1;
if (this.y < 0 || this.y > this.canvas.height) this.vy *= -1;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
}
// 粒子动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
p.update();
p.draw(ctx);
});
requestAnimationFrame(animate);
}// 使用 tsParticles(更简单)
import { tsParticles } from "tsparticles";
tsParticles.load("particles", {
particles: {
number: { value: 80 },
move: { enable: true, speed: 1 },
links: { enable: true, distance: 150 },
shape: { type: "circle" }
}
});实现效果:流动的渐变背景
- Vercel 首页
- OpenClaw 官网
| 技术 | 说明 | 推荐度 |
|---|---|---|
| CSS @keyframes + background-position | 经典方法 | ⭐⭐⭐⭐⭐ |
| CSS background-image + animation | 渐变动画 | ⭐⭐⭐⭐⭐ |
| SVG filter + feTurbulence | 程序化生成纹理 | ⭐⭐⭐⭐ |
| Canvas + gradient | 动态计算渐变 | ⭐⭐⭐⭐ |
/* 流动渐变背景 */
.animated-gradient {
background: linear-gradient(
-45deg,
#ee7752, #e73c7e, #23a6d5, #23d5ab
);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* 柔和光晕渐变 */
.gradient-glow {
background: radial-gradient(
circle at 50% 0%,
rgba(120, 119, 198, 0.5),
transparent 70%
);
}/* 玻璃态渐变卡片 */
.glass-gradient {
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.1),
rgba(255, 255, 255, 0.05)
);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.18);
}实现效果:文字逐字出现、打字机效果
- Stripe 标题动画
- 各类产品 Hero 区
| 技术 | 说明 | 推荐度 |
|---|---|---|
| SplitType.js | 将文字拆分成字符/单词/行 | ⭐⭐⭐⭐⭐ |
| GSAP TextPlugin | 打字机效果 | ⭐⭐⭐⭐⭐ |
| CSS animation + clip-path | 遮罩式文字动画 | ⭐⭐⭐⭐ |
| Motion One | 轻量文字动画 | ⭐⭐⭐⭐ |
// 使用 SplitType + GSAP 实现文字动画
import SplitType from 'split-type';
import gsap from 'gsap';
const text = new SplitType('.hero-text', {
types: 'chars, words'
});
gsap.from(text.chars, {
opacity: 0,
y: 50,
rotateX: -90,
stagger: 0.02,
duration: 0.8,
ease: "power2.out"
});/* 打字机效果 */
.typewriter {
overflow: hidden;
white-space: nowrap;
border-right: 2px solid;
animation:
typing 3s steps(30) forwards,
blink-caret 0.75s step-end infinite;
}
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink-caret {
from, to { border-color: transparent; }
50% { border-color: currentColor; }
}/* 遮罩式文字出现 */
.text-reveal {
clip-path: inset(0 100% 0 0);
animation: reveal 1s ease forwards;
}
@keyframes reveal {
to { clip-path: inset(0 0 0 0); }
}实现效果:卡片翻转、3D 轮播
- Apple 产品展示
- 电商产品列表
| 技术 | 说明 | 推荐度 |
|---|---|---|
| CSS transform: rotateY() | 基础 3D | ⭐⭐⭐⭐⭐ |
| Three.js | 完整 3D 引擎 | ⭐⭐⭐⭐⭐ |
| Spline | 在线 3D 设计工具,可嵌入 | ⭐⭐⭐⭐⭐ |
| React Three Fiber | React 的 Three.js 封装 | ⭐⭐⭐⭐ |
/* 3D 卡片翻转效果 */
.card-container {
perspective: 1000px;
}
.card {
transform-style: preserve-3d;
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.card:hover {
transform: rotateY(180deg);
}
.card-front,
.card-back {
position: absolute;
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}// Three.js 简单的 3D 场景
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 创建 3D 对象
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();<!-- 使用 Spline 嵌入 3D -->
<script type="module" src="https://unpkg.com/@splinetool/viewer@1.0.54/build/spline-viewer.js"></script>
<spline-viewer url="https://prod.spline.design/YOUR_SCENE.splinecode"></spline-viewer>| 场景 | 推荐工具 | 特点 |
|---|---|---|
| 全能型动画 | GSAP | 行业标准,功能最全 |
| React 生态 | Framer Motion | 最流行的 React 动画库 |
| 轻量级 | Motion One, Anime.js | 体积小,性能好 |
| 滚动增强 | Locomotive Scroll, Lenis | 平滑滚动 |
| 页面过渡 | Barba.js, Swup.js | SPA 页面切换 |
| 粒子特效 | tsParticles, PixiJS | 粒子系统 |
| 3D 效果 | Three.js, Spline | 3D 渲染 |
| 数字动画 | CountUp.js | 数字滚动 |
| 文字动画 | SplitType | 文字拆分动画 |
| 工具 | 大小 | 学习曲线 | 性能 | 适用场景 |
|---|---|---|---|---|
| GSAP | ~60kb | 中等 | ⭐⭐⭐⭐⭐ | 复杂动画项目 |
| Framer Motion | ~30kb | 简单 | ⭐⭐⭐⭐ | React 项目 |
| Anime.js | ~15kb | 简单 | ⭐⭐⭐⭐ | 轻量动画 |
| Motion One | ~4kb | 简单 | ⭐⭐⭐⭐⭐ | 追求性能 |
| Lenis | ~10kb | 简单 | ⭐⭐⭐⭐⭐ | 平滑滚动 |
| 趋势 | 特点 | 适合场景 | 案例网站 |
|---|---|---|---|
| 微交互 | 细腻的 hover/click 反馈 | 按钮、卡片、输入框 | Stripe, Figma |
| 滚动叙事 | 随滚动讲故事,沉浸式 | 产品介绍页 | Apple, Awwwards |
| 毛玻璃 | 半透明模糊效果 | 模态框、导航、卡片 | Linear, macOS |
| 流动渐变 | 柔和渐变背景 | Hero 区、背景 | Vercel, OpenClaw |
| 弹性动画 | spring 物理曲线 | 列表加载、拖拽 | Linear, Notion |
| 暗色美学 | 深色+霓虹点缀 | AI/科技产品 | OpenClaw, Vercel |
| 3D 交互 | 可交互 3D 元素 | 产品展示 | Apple, 电商 |
| 性能优先 | 60fps 流畅动画 | 所有场景 | 最佳实践 |
- 动效服务内容 - 动效是为了增强体验,不是炫技
- 性能优先 - 保持 60fps,避免卡顿
- 一致性 - 整个产品使用统一的动效语言
- 可中断 - 用户操作时立即停止动画
- 尊重系统偏好 - 考虑 reduced-motion
- 无障碍优先 - 尊重视障/运动障碍用户的偏好
- 渐进增强 - 低版本浏览器要有合适的降级方案
- 可调试 - 使用 DevTools 持续优化动画性能
实现效果:保证动画流畅 60fps,不卡顿、不耗电
| 属性 | 性能 | 说明 |
|---|---|---|
transform |
⭐⭐⭐⭐⭐ | GPU 加速,最流畅 |
opacity |
⭐⭐⭐⭐⭐ | GPU 加速,触发重绘但不重排 |
filter |
⭐⭐⭐⭐ | 部分 GPU 加速 |
width/height |
⭐⭐ | 触发重排,避免动画 |
left/top |
⭐⭐ | 触发重排,避免动画 |
/* ✅ 正确:使用 transform */
.good-animation {
transition: transform 0.3s ease, opacity 0.3s ease;
}
/* ❌ 错误:使用会触发重排的属性 */
.bad-animation {
transition: left 0.3s ease, top 0.3s ease, width 0.3s ease;
}/* 强制使用 GPU 加速 */
.gpu-accelerated {
transform: translateZ(0);
will-change: transform;
backface-visibility: hidden;
}
/* 组合拳 */
.accelerate {
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000px;
}/* ✅ 最佳实践:动画即将开始前添加 */
.animated-element {
will-change: transform, opacity;
transition: transform 0.3s ease;
}
.animated-element:hover {
transform: translateX(100px);
}
/* ❌ 错误:过早声明或过多属性 */
.too-much {
will-change: all; /* 消耗大量内存 */
}
/* ❌ 错误:动画开始后才添加 */
.element {
transition: transform 0.3s ease;
}
.element.animating {
will-change: transform; /* 太晚了 */
}// 节流 - 用于滚动事件
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用
window.addEventListener('scroll', throttle(() => {
// 滚动时执行的代码
}, 100));
// 防抖 - 用于输入/调整大小
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// 使用
window.addEventListener('resize', debounce(() => {
// 窗口调整大小时执行的代码
}, 250));/* ❌ 错误:读写交替,触发多次重排 */
function badPattern() {
const elements = document.querySelectorAll('.item');
elements.forEach(el => {
const width = el.offsetWidth; // 读 - 触发重排
el.style.width = (width * 2) + 'px'; // 写 - 触发重排
});
}
/* ✅ 正确:批量读写,先读完再写完 */
function goodPattern() {
const elements = document.querySelectorAll('.item');
// 批量读取
const widths = Array.from(elements).map(el => el.offsetWidth);
// 批量写入
elements.forEach((el, i) => {
el.style.width = (widths[i] * 2) + 'px';
});
}
// 或者使用 requestAnimationFrame
function optimizedPattern() {
requestAnimationFrame(() => {
const elements = document.querySelectorAll('.item');
const widths = Array.from(elements).map(el => el.offsetWidth);
elements.forEach((el, i) => {
el.style.width = (widths[i] * 2) + 'px';
});
});
}// 使用 Performance API 检测
function measureAnimationPerformance() {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('动画性能:', entry.name, entry.duration);
if (entry.duration > 16.67) { // 超过一帧
console.warn('动画掉帧警告:', entry.duration);
}
}
});
observer.observe({ entryTypes: ['animation'] });
}
// 使用 Chrome DevTools 检测
// 1. 打开 DevTools (F12)
// 2. Performance 面板
// 3. 录制用户操作
// 4. 查看 Frames-per-second 图表实现效果:让动画对所有用户友好,包括视障、运动障碍用户
/* 检测用户是否偏好减少动画 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
/* 或者完全禁用 */
animation: none !important;
}
}// JavaScript 中检测
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (prefersReducedMotion) {
// 用户偏好减少动画
document.body.classList.add('reduce-motion');
}/* 用户要求时暂停动画 */
.reduce-motion *,
.reduce-motion *::before,
.reduce-motion *::after {
animation-play-state: paused !important;
transition-duration: 0.01ms !important;
}// 自动暂停非必要动画
const pauseOnInteraction = (element) => {
const pauseAnimation = () => {
element.style.animationPlayState = 'paused';
};
const resumeAnimation = () => {
element.style.animationPlayState = 'running';
};
element.addEventListener('mouseenter', pauseAnimation);
element.addEventListener('mouseleave', resumeAnimation);
element.addEventListener('focus', pauseAnimation);
element.addEventListener('blur', resumeAnimation);
};/* 焦点样式 - 确保键盘用户能看到当前位置 */
:focus {
outline: 2px solid var(--focus-color, #1ABC9C);
outline-offset: 2px;
}
:focus:not(:focus-visible) {
outline: none; /* 移除鼠标用户的焦点样式 */
}
:focus-visible {
outline: 2px solid var(--focus-color, #1ABC9C);
outline-offset: 2px;
}
/* 键盘导航的悬停效果 */
@media (hover: none) {
/* 触摸设备:不需要悬停效果 */
.hover-effect {
opacity: 1;
}
}// 键盘导航支持
const handleKeyboardNav = (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
// 触发点击效果
e.target.click();
}
if (e.key === 'Escape') {
// 关闭模态框等
closeModal();
}
};
// 添加到交互元素
document.querySelectorAll('.interactive-card').forEach(card => {
card.setAttribute('tabindex', '0');
card.setAttribute('role', 'button');
card.addEventListener('keydown', handleKeyboardNav);
});<!-- 动态内容区域标记 -->
<div role="region" aria-live="polite" aria-label="实时更新内容">
<!-- 动态内容 -->
</div>
<!-- 加载状态 -->
<div role="status" aria-live="polite">
<span class="loading">加载中...</span>
</div>
<!-- 动画说明 -->
<div aria-describedby="animation-description">
<p id="animation-description" class="sr-only">
图片正在加载,显示一只猫在玩耍
</p>
</div>
<!-- 隐藏屏幕阅读器的装饰性动画 -->
<div aria-hidden="true">
<div class="decorative-animation"></div>
</div>
<!-- 进度指示 -->
<div role="progressbar"
aria-valuenow="75"
aria-valuemin="0"
aria-valuemax="100"
aria-label="文件上传进度">
</div>/* 减少悬停/点击延迟 */
.touch-friendly {
touch-action: manipulation; /* 消除双击缩放 */
-webkit-tap-highlight-color: transparent;
}
/* 增加点击/触摸目标大小 */
.large-target {
min-width: 44px;
min-height: 44px;
padding: 12px 16px;
}
/* 替代悬停的焦点样式 */
@media (hover: none) {
.card {
/* 触摸设备使用边框代替悬停效果 */
border: 2px solid transparent;
}
.card:focus {
border-color: var(--primary-color);
}
}实现效果:确保动画在所有主流浏览器中正常工作
/* WebKit (Safari, Chrome) */
.glass {
-webkit-backdrop-filter: blur(20px);
-webkit-transform: translateZ(0);
-webkit-transition: transform 0.3s ease;
}
/* Firefox */
.glass {
-moz-transform: translateZ(0);
-moz-transition: transform 0.3s ease;
}
/* IE/Edge (旧版) */
.glass {
-ms-transform: translateZ(0);
-ms-transition: transform 0.3s ease;
}
/* 标准写法放最后 */
.glass {
backdrop-filter: blur(20px);
transform: translateZ(0);
transition: transform 0.3s ease;
}/* 检测浏览器是否支持某个特性 */
@supports (backdrop-filter: blur(20px)) {
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
}
}
/* 不支持时的降级 */
@supports not (backdrop-filter: blur(20px)) {
.glass {
background: rgba(0, 0, 0, 0.8);
}
}
/* 检测特定属性 */
@supports (display: grid) {
.grid-layout {
display: grid;
}
}/* 基础样式 - 所有浏览器 */
.fade-in {
opacity: 0;
}
/* 增强样式 - 支持 CSS 动画的浏览器 */
@supports (animation: fadeIn 0.3s ease) {
.fade-in {
animation: fadeIn 0.3s ease forwards;
}
}
/* 高级效果 - 支持 backdrop-filter 的浏览器 */
@supports (backdrop-filter: blur()) {
.modal-backdrop {
backdrop-filter: blur(10px);
background: rgba(0, 0, 0, 0.5);
}
}// 检测动画支持
const supportsAnimation = () => {
return typeof Animation !== 'undefined';
};
// 检测 Intersection Observer
const supportsIntersectionObserver = () => {
return 'IntersectionObserver' in window;
};
// 检测 WebGL
const supportsWebGL = () => {
try {
const canvas = document.createElement('canvas');
return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
} catch (e) {
return false;
}
};
// 降级方案
if (!supportsIntersectionObserver()) {
// 使用 scroll 事件作为回退
window.addEventListener('scroll', handleScroll);
}| 特性 | Chrome | Firefox | Safari | Edge | IE11 |
|---|---|---|---|---|---|
backdrop-filter |
76+ | 103+ | 9+ | 17+ | ❌ |
transform: translate3d() |
36+ | 16+ | 9+ | 12+ | 10+ |
@keyframes |
43+ | 16+ | 9+ | 12+ | 10+ |
will-change |
36+ | 36+ | 9.1+ | 79+ | ❌ |
IntersectionObserver |
51+ | 55+ | 12.1+ | 15+ | ❌ |
scroll-behavior: smooth |
61+ | 36+ | 15.4+ | 79+ | ❌ |
prefers-reduced-motion |
74+ | 63+ | 10.5+ | 79+ | ❌ |
<!-- 自动前缀 - PostCSS autoprefixer -->
<script src="https://cdn.jsdelivr.net/npm/autoprefixer@10.4.16/lib/index.min.js"></script>
<!-- Intersection Observer Polyfill -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"></script>
<!-- Smooth Scroll Polyfill -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=scroll-behavior"></script>
<!-- CSS Custom Properties Polyfill (旧浏览器) -->
<script src="https://cdn.jsdelivr.net/npm/css-vars-ponyfill@2.4.8/dist/css-vars-ponyfill.min.js"></script>实现效果:快速定位动画问题,优化性能
- 打开 DevTools (F12)
- 按
Ctrl+Shift+P(Windows) 或Cmd+Shift+P(Mac) - 输入 "Show Animations"
- 打开 Animations 面板
- 录制动画:自动捕获页面动画
- 播放控制:暂停、减速、加速播放
- 时间线:查看每个动画的时长和触发时机
- 性能分析:检查是否掉帧
// 启用 GSAP 调试模式
gsap.config({ trial: true });
// 添加日志
gsap.to(element, {
x: 100,
onUpdate: () => console.log('动画进行中'),
onComplete: () => console.log('动画完成')
});
// GSAP Inspector (Chrome 扩展)
// https://chrome.google.com/webstore/detail/gsap-inspector// Performance Observer - 监控长任务
const perfObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'longtask') {
console.warn('长任务检测:', entry.duration, 'ms');
}
});
});
perfObserver.observe({ entryTypes: ['longtask'] });
// Frame Timing
const frameObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.duration > 16.67) {
console.warn('掉帧:', entry.duration.toFixed(2), 'ms per frame');
}
});
});
frameObserver.observe({ entryTypes: ['frame'] });// 查看当前页面的所有 CSS 动画
const getAllAnimations = () => {
const elements = document.querySelectorAll('*');
const animations = [];
elements.forEach(el => {
const styles = getComputedStyle(el);
if (styles.animationName !== 'none') {
animations.push({
element: el,
name: styles.animationName,
duration: styles.animationDuration,
delay: styles.animationDelay
});
}
});
console.table(animations);
return animations;
};
// 检测动画性能
const checkAnimationPerformance = () => {
const elements = document.querySelectorAll('*');
let slowAnimations = 0;
elements.forEach(el => {
const styles = getComputedStyle(el);
const duration = parseFloat(styles.animationDuration);
if (duration > 1 && duration < 10) {
// 动画时长超过1秒且非关键动画
slowAnimations++;
el.style.outline = '2px solid red'; // 标红
}
});
console.warn(`发现 ${slowAnimations} 个可能影响性能的动画`);
};
// 禁用所有动画(测试降级效果)
const disableAllAnimations = () => {
document.body.style.transition = 'none';
document.body.style.animation = 'none';
console.log('已禁用所有动画');
};| 工具 | 用途 | 链接 |
|---|---|---|
| Chrome DevTools Animations | 动画录制和分析 | 内置 |
| GSAP Inspector | GSAP 动画调试 | Chrome 商店 |
| Motion DevTools | Framer Motion 调试 | Chrome 商店 |
| Lighthouse | 性能审计 | 内置 |
| WebPageTest | 线上性能测试 | webpagetest.org |
| PageSpeed Insights | Google 性能评分 | pagespeed.web.dev |
// Lighthouse CLI 检查动画性能
// lighthouse https://example.com --output=json --output-path=report.json
//
// 关注指标:
// - Uses inefficient CSS properties
// - Total main-thread time
// - Avoid large layout shifts以 DN 游戏前端为例,展示渐进式动画优化
/* 选项卡片依次滑入 */
.option-card {
opacity: 0;
transform: translateX(30px);
animation: slideIn 0.4s ease forwards;
}
.option-card:nth-child(1) { animation-delay: 50ms; }
.option-card:nth-child(2) { animation-delay: 150ms; }
@keyframes slideIn {
to {
opacity: 1;
transform: translateX(0);
}
}/* 选项卡片悬浮 */
.option-card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.option-card:hover {
transform: translateX(5px) scale(1.02);
box-shadow: 0 0 20px rgba(26, 188, 156, 0.4);
}
/* 按钮涟漪效果 */
.btn::after {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%);
transform: scale(0);
transition: transform 0.5s ease;
}
.btn:hover::after {
transform: scale(2);
}// 使用 Intersection Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1 });
// 观察剧情文本
document.querySelectorAll('.scene-content').forEach(el => {
el.classList.add('scroll-reveal');
observer.observe(el);
});.scroll-reveal {
opacity: 0;
transform: translateY(30px);
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.scroll-reveal.visible {
opacity: 1;
transform: translateY(0);
}// 增强版打字机
function typeWriter(element, text, speed = 50) {
let i = 0;
element.classList.add('typing');
function type() {
if (i < text.length) {
element.textContent += text.charAt(i);
i++;
setTimeout(type, speed);
} else {
element.classList.remove('typing');
element.style.borderRightColor = 'transparent';
}
}
type();
}.typing {
border-right: 2px solid var(--primary-color);
animation: blink 0.75s step-end infinite;
}
@keyframes blink {
50% { border-color: transparent; }
}// 使用 GSAP 实现流畅的选项切换
import { gsap } from 'gsap';
// 选项卡片切换动画
function animateOptionChange(oldCard, newCard) {
const tl = gsap.timeline();
// 旧卡片退出
tl.to(oldCard, {
opacity: 0,
x: -50,
duration: 0.3,
ease: 'power2.in'
});
// 新卡片进入
tl.from(newCard, {
opacity: 0,
x: 50,
duration: 0.4,
ease: 'back.out(1.7)'
}, '-=0.1');
}
// 剧情文本打字机效果
function animateText(element, text) {
gsap.to(element, {
textContent: text,
duration: text.length / 20,
ease: 'none',
snap: { textContent: 1 }
});
}// 简单的背景粒子
class ParticleBackground {
constructor(container) {
this.container = container;
this.particles = [];
this.init();
}
init() {
// 创建 canvas
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.container.appendChild(this.canvas);
// 创建粒子
for (let i = 0; i < 50; i++) {
this.particles.push(new Particle(this.canvas));
}
this.animate();
window.addEventListener('resize', () => this.resize());
}
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.particles.forEach(p => {
p.update();
p.draw(this.ctx);
});
requestAnimationFrame(() => this.animate());
}
resize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
}// 检测并应用用户偏好
const motionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
function handleMotionPreference() {
if (motionQuery.matches) {
document.body.classList.add('reduce-motion');
// 禁用所有复杂动画
disableComplexAnimations();
} else {
document.body.classList.remove('reduce-motion');
enableAnimations();
}
}
motionQuery.addEventListener('change', handleMotionPreference);
handleMotionPreference();@media (prefers-reduced-motion: reduce) {
.particle-bg,
.typewriter,
.scroll-reveal,
.option-card {
animation: none !important;
transition: none !important;
opacity: 1 !important;
transform: none !important;
}
}| 网站 | 行业 | 动效亮点 |
|---|---|---|
| Stripe | 金融支付 | 数字滚动、流畅滚动、微交互 |
| Linear | 项目管理 | 丝滑过渡、列表动画、模糊效果 |
| Apple | 科技硬件 | 产品轮播、3D效果、视差滚动 |
| Airbnb | 旅游住宿 | 地图交互、卡片悬浮、搜索动画 |
| OpenClaw | AI助手 | 深色主题、暗色模式切换 |
| Notion | 生产力 | 简洁过渡、模态框动画 |
| Figma | 设计工具 | 实时协作、面板动画 |
| Vercel | 部署平台 | 3D地球、渐变动画 |
| Spotify | 音乐 | 波形可视化、迷你播放器 |
| Awwwards | 设计平台 | 滚动触发、视差、粒子效果 |
文档创建时间:2026-03-20 最后更新:2026-03-21 整理者:姜妙鱼 🐟
- ✅ 滚动触发动画 (Scroll-triggered)
- ✅ 数字滚动动画 (Count-up Animation)
- ✅ 视差滚动 (Parallax Scrolling)
- ✅ 模糊效果动画 (Blur/Glassmorphism)
- ✅ 页面过渡转场 (Page Transitions)
- ✅ 悬停微交互 (Hover Micro-interactions)
- ✅ 粒子效果 (Particle Effects)
- ✅ 渐变动画 (Gradient Animation)
- ✅ 文字动画 (Text Animations)
- ✅ 3D 变换与交互 (3D Transforms)
- ✅ 主流动效工具栈
- ✅ 设计趋势总结
- ✅ 新增:性能优化 (Performance Optimization)
- ✅ 新增:无障碍设计 (Accessibility / A11y)
- ✅ 新增:浏览器兼容性 (Browser Compatibility)
- ✅ 新增:调试工具 (Debugging Tools)
- ✅ 新增:实践案例(从简单到高级的动画升级路径)