# 滚动叙事 ## 落地页的滚动动效 落地页、品牌页、产品发布页和展览页,滚动动效和 [动效](motion.md) 的三处基本动效一起验收;文档、文章、工具和后台不做。用成熟的动效库实现,见下文“动效库”。 **必须有两样**:首屏以下的区块按内容出场;至少一段滑动驱动的叙事,主角在滚动里发生明显变化。**手法按页面挑**:首屏景深、字标收进导航、一镜到底、章节转场镜头、背景随章节变色、宣言逐字亮起,从这个页面的主视觉和内容里选合适的,写进分镜并说明为什么选它。下面先说首屏景深,它是首屏有主视觉和大标题时最常用的一种。 ### 首屏景深(适合首屏有主视觉和大标题的页面) 首屏是一个固定住的舞台,滚动直接驱动里面的层次变化,往回滚就倒放: - 首屏固定 100–200vh 的滚动距离,窄屏可缩到 80–120vh。 - 至少两层以不同速度、不同方向变化。最常用的是主视觉和大标题反向缩放:主视觉从 1 缩到 0.8,标题从 1 放大到 1.25;或者反过来,主视觉推近、标题后退。背景层动得最慢,前景层最快。 - 幅度要大到录屏里一眼看出来:主层缩放不少于 15%,或位移不少于 15vh。小于这个幅度,看起来就是页面在普通滚动。 - 大标题是图形层,可以缩放和视差;正文、按钮和表单不缩放、不做视差,固定后保持可读可点。 - 结束状态要交接给下一节:主视觉缩到下一节的位置,标题退成背景纹理,或者画面让出一条路给下一节的主角。不要固定结束后整块直接被推走。 首屏是满版的品牌字标时,用下面的“字标收进导航”。首屏是其他满版文字、产品界面或纯排版时,不一定适合景深,可以把滑动驱动的叙事放在后面。 ### 字标收进导航(适合首屏是满版品牌字标的页面) 首屏就是品牌名本身,滚动时它缩成导航栏里的标志。它用一个元素同时完成满版文字骨架和一段滑动驱动的叙事,适合品牌名短、字形有性格的工作室、品牌和作品集: - 首屏只有这一个字标,撑满版心宽度,窄屏也保持一行撑满;导航里不再放第二个标志。 - 滑动驱动,滚过 60–100vh,字标沿一条路径缩到导航标志的位置和尺寸,往回滚放大回来。结束状态就是导航里的标志,位置和尺寸按导航实际量出,交接时不跳。 - 缩放同一个元素的变换,不动画字号;字标用 SVG,或按容器宽度算出的字号。 - 字标让出首屏的同时,下一节内容已经进入画面,不留一整屏空白。 - 字标从满版缩成导航标志,是主角明显的缩放和一次交接,算一段滑动驱动的叙事;同一页不再另做首屏景深。 - 减少动态效果时,字标留在首屏不缩放,导航从一开始就显示标志。 ### 区块按内容出场(必须,滑动触发) 首屏以下的每个区块,滚到位置时出场一次,往回滚不重播。出场方式从这个区块的内容和材质推出来,并且符合物理直觉:有重量的落下会过冲后稳住,轻的东西有空气阻力,机械的东西咔嗒到位。 | 区块内容 | 出场方式 | | --- | --- | | 卡片、实物、价格牌 | 带重量落下后稳住,过冲幅度见 [动效](motion.md) 的“手感”;后一张被前一张带出 | | 列表、时间线、步骤 | 沿阅读方向依次展开,连接线先画出,节点随后落位 | | 数字、指标 | 滚到目标值,高位先停、末位后停;不从 0 起跳的用原值起滚 | | 线条、图表、路径 | 沿数据或流程的方向描出,端点落定时轻微放大一下 | | 图片、照片 | 遮罩从画面主体的方向揭开,图片同时从 1.08 回缩到 1 | | 纸、布、标签 | 先快后慢,带一点旋转后摆正,像被放到桌上 | | 金属、机械、硬件 | 短促到位,没有软弹,可以带一次很小的回震 | | 大标题、口号 | 按词或按行从遮罩里升起,字距从略松收紧 | 规则: - 每个区块的出场写进分镜。同一页最多两个区块用同一种出场。 - 曲线用弹簧或惯性,参数从 [动效](motion.md) 的“手感”表里按材质取,不用默认的 ease。 - 主角先到,其余被带出,间隔 40–80ms,单个区块的出场总长不超过 900ms。 - 全页每个区块套同一个淡入上移,不算完成这一层。 ### 滑动驱动的叙事(必须至少一段) 可以是首屏景深、字标收进导航,也可以是页面中段一段一镜到底,规则见下一节。主角必须在滚动里发生明显变化:缩放、拆解、变形、穿过或形状接力。一个小点沿着线移动、节点逐个点亮,只能算主叙事里的一个细节,不能单独当作主叙事。 ### 分镜 动手前在方向卡的“动效”一栏写出滚动分镜:选了哪些手法、为什么,每一段占多少滚动距离、主角是谁、每个镜头画面里有什么、什么在动、往哪个方向、文字什么时候出现。先拆两个同类顶级落地页的滚动节拍作参照,写清它们每一段在动什么,再写自己的。 ## 视差与一镜到底 - **一镜到底。** 整段是一次不切换的镜头。一个主角从头走到尾,可以是产品、一根线、一个形状或一个字,每一步长成、变成或让出下一个画面:推近看到细节,拉远看到全貌,转过去看到背面,穿过去进入下一个场景。 - **主角从产品里找。** 主角是这个产品处理的那样东西,在滚动里走完它自己的过程。找不到只属于这个产品的主角时,退回下面的转场手法,不用通用的漂浮几何。 - **停下来再说话。** 每个镜头留一段静止,文字在静止时出现;边动边读很累。 - **视差要有真实的前后。** 只在画面本来就有远近层次时用:前景的物体、中景、远处的背景,越近动得越多,差别要小。正文、按钮和表单不做视差;大标题作为图形层时,按上面的首屏景深处理。 - **转场也是镜头。** 一个圆从某一点扩开,带出下一节;推进一张图,穿过它到达下一节;背景色在章节之间随阅读慢慢变;一句宣言随滚动逐字亮起。每种手法一页只用一次。 - **倒着滚也成立。** 每一帧只由滚动位置决定,往回滚自然倒放,刷新或跳到中间也立刻是对的画面。不接管用户的滚动。 - **留出口。** 长段落前给一个跳过入口;减少动态效果时,把每个静止画面按顺序排成普通区块。 - **代码做不出来的,交给视频。** 用户想要很强的首屏动画,而效果要靠生成视频或序列帧才做得出来,例如角色转身、产品拆解、镜头穿越场景,可以告诉用户用 [oil-motion](https://github.com/oil-oil/oil-motion) 来做。CSS、SVG、着色器能完成的仍自己做;同一次对话只提一次。 ## 滚动交互的两种模式 滚动带来的变化分两种模式: - **滑动驱动(Scroll-Driven)。** 动画进程与滚动距离严格 1:1 映射(Scrub)。用户停下则动画停下,往回滚则倒放。首屏景深、一镜到底、3D 视角变换和模型解构只用滑动驱动;除首屏景深外,一镜到底一页最多一段。 - **滑动触发(Scroll-Triggered)。** 元素滚入视口阈值时,触发一段按自身时长播放的独立动画(如卡片进场、数字上涨)。它什么时候播完由代码决定,不跟着滚动条走。 - **默认单向一次性(Once)。** 触发后样式固定,用户向上回滚不重播、不复位,不在阅读中途让内容反复飞入或闪烁。 - **离开重置(Reset on Leave)。** 只有强节奏的纯展示页才允许在完全移出视口后重置,不在视口临界点反复触发。 ## 平滑滚动与全屏分段 - **平滑滚动只管滚起来顺不顺,不算动效。** 用 Lenis 这类库,是为了消掉鼠标滚轮一格一格的跳动,让滑动驱动的动画和视差走得均匀。后台、仪表盘、表单和长文档不开全局平滑滚动,保持原生滚动的即时响应。 - **慎用全屏分段滚动(Snap Scroll)。** 隐藏滚动条、单次滑动切换整屏的做法只适合特定的全屏展厅与作品封面,常规业务和长文本不用。 ## 动效库 落地页的滚动动效必须用成熟的动效库,不手写滚动监听和逐帧计算: - **没有框架的页面**:GSAP,滚动用 ScrollTrigger(`scrub` 做滑动驱动,`once` 做滑动触发,`pin` 固定舞台),大标题拆字用 SplitText,元素换位置用 Flip。平滑滚动用 Lenis,并接进 GSAP 的时钟:`lenis.on('scroll', ScrollTrigger.update)`、`gsap.ticker.add((t) => lenis.raf(t * 1000))`、`gsap.ticker.lagSmoothing(0)`。GSAP 和它的插件都可以免费使用。 - **React、Vue 等项目**:沿用项目已有的动效库(Motion、GSAP 等);没有时加 GSAP,不另外手写一套。 - **需要离线打开的作品**:把库文件按固定版本放进作品目录,从本地引用,不依赖 CDN。 - **减少动态效果**:用 `gsap.matchMedia()` 分开两套:减少时不固定、不缩放,所有区块直接到位,主叙事排成按顺序的静止画面。 - 只动变换、透明度和滤镜。固定舞台的外层高度就是这段的滚动距离;离屏的动画由库自动暂停。窄屏可以缩短距离、降低幅度,但选定的手法都要保留。 ## 检查 从头滚到底,再滚回去,各看一遍:往回滚是否倒放、跳到中段刷新画面是否正确、文字是否在静止时出现、窄屏选定的手法是否都在、开启“减少动态效果”后是否所有内容直接可读。