Communitygithub.com

苹果式滚动动画

使用纯 HTML/CSS/JS 构建苹果风格的滚动驱动动画(滚动讲述),无需任何库。当用户想要页面元素随着滚动而组装、点亮、倾斜、展开或切换时使用,就像 apple.com 产品页面那样。涵盖了固定(sticky)区块、滚动进度控制、逐词显示、元素飞入以及无头测试方法。

苹果式滚动动画 是什么?

该技能为开发者提供了一套完整的方法论和现成的代码引擎,用于创建像苹果官网产品页面那样高度精细的滚动驱动动画。其核心思想是利用滚动位置作为动画的“进度条”,而不是依赖计时器,从而让滚动行为自然可控,并且支持反向滚动回放动画。通过“固定”、“进度”、“驱动视觉效果”三个核心概念,可以组合出组装、逐词点亮、倾斜展平、展开等多种效果。技能文档不仅提供了每种效果的具体实现技巧和已实践验证的规则(如使用独立 CSS 属性避免与悬停状态冲突、控制滚动距离等),还包含了无头 Chrome 测试方案和交付检查清单。该技能适用于任何支持纯前端技术栈的平台(Claude Code、Cursor、Codex 等),帮助开发者快速构建媲美苹果官网的滚动叙事体验。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/MananShukla007/apple-scroll-animation/tree/HEAD/skills/apple-scroll-animation

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

苹果式滚动动画 是做什么的?

效果由滚动位置控制,而非由计时器触发。向上滚动会反向播放动画。无需库。

三个核心思想

  1. 固定。一个高的容器(例如 height: 300vh)包含一个 position: sticky; top: 0; height: 100vh; overflow: hidden 的子元素。该子元素在容器滚动时保持固定在屏幕上。容器额外的vh就是你的动画预算。
  2. 进度。一个函数将滚动位置转换为 0..1 之间的数字:
    • 固定区块:clamp(-rect.top / (rect.height - innerHeight))
    • 元素进入视口:clamp((innerHeight*a - rect.top) / (innerHeight*(a-b)))
  3. 用进度驱动视觉。每帧设置 translate、rotate、scale、opacity(以及 borderRadius)。一个使用 requestAnimationFrame 节流的 scroll 监听器重新计算所有效果。

即用即贴引擎:references/scroll-engine.js。

效果很好的方案(选 3-5 个,不要全用)

效果如何实现
组装元素从视口边缘散落(随机角度、旋转、缩放 .35、透明度 .2)逐渐过渡到其布局位置。在加载/调整大小时计算出每个元素到其自然位置的偏移量,然后乘以 (1 - ease(p))。按索引交错。
逐字点亮将每个词包裹在 span 中。透明度 .18 → 1,使用 clamp(p * 1.25 * N - k)。
固定步骤step = floor(p * N);分数部分 p*N - step 填充当前步骤内部的进度条。点击步骤应 scrollTo 该步骤的位置。
倾斜展平perspective(1400px) rotateX((1-e)*22deg) translateY((1-e)*60px) scale(.84 + .16*e) 用于手机/设备模型。
卡片升起translate: 0 (1-e)*80px; scale: .9+.1e; opacity: e,按列延迟 (i % cols)。
展开视频/图片 scale .78 → 1 且 borderRadius 44px → 28px。

在应用进度之前使用 ease = t => 1 - (1-t)**3。

规则(经验教训)

  • 使用独立的 CSS 属性 translate、rotate、scale 进行进度控制,将 transform 留给悬停。否则悬停和滚动会争夺同一个属性。
  • 不要在同一元素上结合 .reveal 渐变类与进度控制的变换。选择一种。
  • 将区块标题放在固定面板内与内容在一起。如果面板仅包含内容且居中,高显示器会出现大片空白。
  • 保持滚动距离适中。对于 N 步步骤,约为 N * 55vh + 100vh;对于一次性效果,为 240-300vh。用户会觉得 700vh+ 很累。
  • 限制固定内容不超过 100vh。在短屏幕(max-height: 820px)和手机上,隐藏副标题和额外内容,步骤中只显示当前步骤。
  • 减少动画偏好:如果 prefers-reduced-motion: reduce,则返回进度 1(最终状态,无动画)。不要隐藏元素。
  • 祖先元素上 sticky 不需要设置 overflow,除了 body 上的 overflow-x: hidden,这是可以的。避免在 sticky 元素和页面之间的任何容器上设置 overflow: hidden。
  • 调整大小时重新计算(组装的偏移量取决于布局)。
  • 仅对 translate/rotate/scale/opacity/border-radius 做动画;避免使用布局属性。
  • 避免微小的视频首尾段:如果使用 <video> 播放进行进度控制,短片段可能渲染为空白。

典型页面顺序

英雄区(固定、组装) → 一句普通陈述(无效果) → 验证/电影(展开) → 固定步骤 → 设备模型(倾斜展平) → 卡片网格(卡片升起) → 行动号召。在黑色和浅灰色区块之间交替以营造苹果感觉;使用一种强调色。

测试

无头 Chrome 的 --screenshot 无法滚动。需通过开发者工具协议驱动真实 Chrome:

  1. chrome --headless=new --remote-debugging-port=9333 --user-data-dir=/tmp/prof about:blank &
  2. 从 Node(v22+ 支持全局 WebSocket):获取 http://localhost:9333/json,打开页面的 webSocketDebuggerUrl,发送 Emulation.setDeviceMetricsOverride、Page.navigate,然后对每个位置执行 Runtime.evaluate("scrollTo(0,Y)"),等待约 700 毫秒,Page.captureScreenshot。
  3. 从各区块的 offsetTop 和高度中选择 Y(例如,每个固定区块的 0%、60%、100%)。
  4. 在桌面端 (1440x900)、大屏幕 (2000x1300) 和手机端 (390x800) 检查,并确认 document.documentElement.scrollWidth === innerWidth(无水平溢出)。

交付检查清单

  • 每个效果由滚动进度驱动,可逆
  • 减少动画偏好降级
  • 检查手机布局,无水平滚动
  • 固定滚动长度适中;高屏幕无空白
  • 在每个固定区块的开始/中间/结束处截图

相关技能