苹果式滚动产品叙事:GSAP、Three.js 与性能工程
Category(分类): Visualization Status: 已读
相关资料:GSAP 文档 · GSAP Timeline · Three.js Scene · Three.js WebGLRenderer。 本文整理产品介绍页随滚动展开的常见实现思路。苹果官网等大型站点的具体实现会随页面变化,不能简单认定都使用 GSAP;重点是理解“滚动叙事”的通用技术组合。
一、它不是一种动画,而是一套滚动叙事
“产品随着页面滚动自然变化”的体验通常称为 滚动驱动动画(scroll-driven animation) 或 scrollytelling。用户并非只是在浏览一张长页面,而是在用滚动进度控制一段产品分镜:
进入章节
→ 视觉内容吸顶停留
→ 滚动进度映射到 0~1
→ 文案、素材、相机或图表按进度变化
→ 章节完成,解除吸顶并进入下一幕
典型场景包括产品旋转拆解、镜头推进、颜色切换、参数展开、文案分层出现,以及将多段页面内容串成一个连续故事。
二、GSAP 和 Three.js 的区别
| 对比项 | GSAP | Three.js |
|---|---|---|
| 本质 | 属性动画与时间线编排库 | 基于 WebGL 的 3D 渲染库 |
| 核心工作 | 计算对象属性如何随时间变化 | 创建并绘制场景、相机、模型、灯光和材质 |
| 可操作对象 | DOM、CSS、SVG、Canvas 或任意 JavaScript 对象 | Scene、Camera、Mesh、Geometry、Material、Light 等 |
| 是否负责绘制画面 | 否 | 是 |
| 常见使用场景 | 文案、卡片、SVG、滚动触发和页面转场 | 3D 模型、粒子、地球、虚拟场景和实时 WebGL 特效 |
GSAP 的 Tween 是高性能的属性变化器,Timeline 用于精确编排多个 Tween;Three.js 则需要用 Scene + Camera + WebGLRenderer 将 3D 世界渲染到画布上。
三、两者如何配合
Three.js 负责画出 3D 场景,GSAP 负责把相机或模型的属性随滚动/时间平滑变化。GSAP 不需要特殊插件就能处理 Three.js 对象的普通属性:
// GSAP 驱动 Three.js 模型和相机的属性
gsap.to(mesh.rotation, {
y: Math.PI * 2,
duration: 2,
ease: 'power2.inOut'
})
gsap.to(camera.position, {
z: 3,
duration: 1.2
})
不过属性变化后,Three.js 仍必须执行渲染:
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
})
若关闭 matrixAutoUpdate,修改物体变换后还要主动调用 object.updateMatrix()。简单页面可在 GSAP 的 onUpdate 中按需渲染;有 OrbitControls、实时光效、粒子等持续变化时,保持合理的渲染循环更直接。
四、真实产品页常用的视觉方案
高质量页面不一定实时渲染 3D。选素材方案时,要按交互需求与性能预算决定:
| 方案 | 优点 | 局限 | 适合内容 |
|---|---|---|---|
| 图片序列帧 + Canvas | 视觉稳定、可精确控制每一帧、适合滚动推进 | 资源多,需要预加载与缓存策略 | 产品旋转、拆解、固定镜头动画 |
| 视频 | 画质高、制作流程成熟 | 难按帧精确交互;移动端自动播放限制较多 | 不需要用户控制镜头的品牌镜头 |
| 分层图片 + CSS/GSAP | 成本低,适合制造景深和进入动效 | 不是真实 3D,视角自由度有限 | 多层视差首屏、海报式叙事 |
| Three.js / WebGL | 可实时旋转模型、改变相机、灯光和粒子 | 开发、资源与性能成本最高 | 可交互 3D 模型、空间场景、实时特效 |
| SVG / DOM + GSAP | 文字和界面细节清晰、易适配 | 不适合复杂真实感三维画面 | 文案、参数、图标、数据展示 |
很多产品页是混合方案:首屏用分层图片,产品旋转使用 Canvas 序列帧,说明文案用 GSAP,只有用户能自由操作的模型才使用 Three.js。
五、滚动进度与吸顶分镜
实现核心不是“监听滚动后切一个 class”,而是建立连续的进度映射:
章节滚动范围:300vh
├─ 0%~20%:标题淡入、产品出现
├─ 20%~70%:序列帧/相机持续推进
├─ 70%~90%:参数与卖点展开
└─ 90%~100%:视觉淡出,交给下一章节
为让用户有足够滚动距离控制一段画面,视觉区域常用 position: sticky 或动画库的 pin 功能固定在视口内;文章容器则提供 200vh、300vh 甚至更长的滚动距离。GSAP ScrollTrigger 很适合管理这一模式:它可以将滚动位置绑定到 Timeline,并提供 pin、scrub、断点和清理能力。
但同类效果也能以 CSS Scroll-driven Animations、原生 requestAnimationFrame + scroll progress,或框架/自研动画系统实现。GSAP 是高效选择,不是唯一答案。
六、性能决定体验上限
动画库无法替代资源工程。序列帧、视频和 WebGL 模型如果未处理好,即使时间线再漂亮也会卡顿。
6.1 序列帧与图片
- 首屏只预加载必要帧,后台逐步加载后续帧;
- 缓存当前帧附近的前后帧,快速滚动时避免频繁请求;
- 使用合适的尺寸、现代图片格式和多断点资源,不让移动端下载桌面原图;
- Canvas 绘制前处理好解码与容器尺寸,避免在滚动回调中进行昂贵计算;
- 对跳帧、资源失败和弱网提供可阅读的静态首帧。
6.2 WebGL 与渲染循环
- 控制模型面数、纹理尺寸、阴影与后处理数量;
- 页面不可见、章节离开视口或标签页隐藏时暂停/降频;
- 不在每个滚动事件中直接做大量计算,利用
requestAnimationFrame统一更新; - 针对低性能设备降低像素比、模型精度或改用预渲染素材;
- 释放不再使用的 geometry、material、texture 与 renderer,避免 GPU 内存泄漏。
七、响应式、可访问性与生命周期
响应式不是等比缩放
移动端应重新审视镜头、裁切、素材层级、滚动距离和文案节奏。桌面端横向展开的产品拆解,在手机上可能需要改为纵向分镜甚至静态图文,而不是把所有内容缩小。
尊重减少动态效果偏好
对于 prefers-reduced-motion: reduce:
- 取消大幅视差、自动循环和快速镜头运动;
- 直接显示关键画面和完整文案;
- 保留键盘操作、阅读顺序与核心功能;
- 不把“动画播放完成”作为用户能继续操作的前提。
单页应用中的清理
在 Vue/Nuxt 等应用中,DOM、Canvas 与 WebGL 都应仅在客户端初始化。路由切换、组件卸载或断点变化时,需要销毁 ScrollTrigger/事件监听、停止渲染循环、清理 Three.js 资源和 Canvas 引用;否则容易出现重复绑定、持续渲染和内存增长。
八、从分镜开始,而不是从库开始
建议的实施顺序:
- 先写出每一章节的核心信息、初始状态、终止状态与用户应理解的内容;
- 为每段选择最低成本的视觉方案:静态图、分层图、序列帧、视频还是实时 3D;
- 用 GSAP Timeline 或其他机制编排文案与视觉的进出顺序;
- 在真实移动设备和弱网络下测试素材加载、掉帧和滚动手感;
- 补齐减少动态效果、资源失败、键盘访问与生命周期清理;
- 最后才微调缓动、速度与装饰性细节。
总结
“苹果式”产品介绍页的关键不是某一个库,而是 内容分镜 + 滚动进度映射 + 合适素材方案 + 性能工程 + 可访问性降级 的协同。GSAP 擅长时间线、文字/SVG/界面和滚动编排;Three.js 擅长实时 3D;序列帧、视频和分层图片则常以更低的成本交付高质量视觉效果。