mcpField
S
scroll-and-webgl

scroll-and-webgl

github.com/paragonhq设计与 UI044 次安装5 周前更新
代码仓库

关于 scroll-and-webgl

面向营销页面滚动特效、WebGL 与 Canvas 场景的设计技能,提供注重性能和无障碍的预算与实现指导。适合制作表现力丰富网页,同时确保脚本运行前文本可见,并提供减少动态效果及无 JavaScript 回退的开发者。

主要功能

  1. 01按复杂度划分滚动动画方案
  2. 02滚动特效的性能预算
  3. 03文本显现与无障碍指导
  4. 04Canvas 和 WebGL 资源管理
  5. 05延迟加载与加载顺序
  6. 06减少动态效果及无 JavaScript 回退

适用场景

  1. 01为营销页面添加滚动显现效果
  2. 02构建固定或滚动联动场景
  3. 03创建带静态回退的 WebGL 首屏
  4. 04确保无 JavaScript 时页面内容仍可见

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/paragonhq/stealth-skills --skill scroll-and-webgl

安装后在 Claude Code 中输入/scroll-and-webgl确认已加载。

详细介绍

滚动与 WebGL

这是唯一一个允许以动态效果为核心的层级。规则不是更宽松,而是更严格,因为失败的结果可能是:页面在作者的笔记本电脑上很漂亮,在其他地方却无法使用。

适用场景

场景是否允许
营销页面、发布页面、作品集、案例研究可以,但须遵守下方的预算
文档、博客、阅读内容最多使用标题揭示效果
产品 UI、仪表板、工具、设置不允许。请改用 motion 技能

如果有人提议在产品界面上添加滚动效果,答案就是不行,原因是人们会数百次使用产品界面。

预算

开始前设定,结束时检查:

  • 在 CPU 降速 4 倍的情况下达到 60fps,覆盖整个滚动过程。每秒掉一帧就算不合格。
  • LCP 低于 2.5s,且效果已启用。主视觉区域的文字必须位于 HTML 中,并在任何脚本运行前可见。
  • INP 低于 200ms:滚动处理程序绝不读取布局;所有操作都在合成器上进行,或批量放入 requestAnimationFrame。
  • 内存:每个页面只能有一个 WebGL context。纹理尺寸低于 2048px。组件卸载时释放资源。
  • 每个视口只用一种视觉效果。 主视觉区域着色器 或 固定滚动场景 或 拆分文本揭示效果,同一时间只能使用一种。两种同时出现就会显得杂乱。

滚动驱动效果,按成本从低到高排列

1. CSS 滚动驱动动画

无需 JavaScript,在合成器上运行,只需一条媒体查询即可遵循减少动态效果偏好:

.reveal {
  animation: fade-up linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 40%;
}
@keyframes fade-up { from { opacity: 0; transform: translateY(24px); } }

适用于:进入视口时揭示、进度条、幅度低于 10% 的视差、收缩式粘性页眉。不支持的浏览器会回退到“直接显示”,这是正确的回退方式。

2. IntersectionObserver + 类名

适用于 CSS 时间线不受支持,或希望使用库的入场效果时的一次性揭示效果。观察元素、添加类名、取消观察。阈值为 0.15–0.3;设置 rootMargin: "0px 0px -10% 0px",让元素在到达底边前稍早揭示。

3. GSAP ScrollTrigger

适用于任何需要滚动同步、固定或按顺序播放的效果:

  • 使用 scrub: true(或 0.5–1,以增加少量延迟)将时间线与滚动条关联。没有其他方式能达到同样流畅的效果。
  • 使用 pin: true,让场景播放期间固定某个区段;固定区段的滚动距离应低于 300vh,否则用户容易迷失。
  • 在固定元素上设置 anticipatePin: 1,避免出现一帧的跳动。
  • 每个场景使用一个 ScrollTrigger,而不是每个元素一个;在时间线内排列元素。
  • 使用 matchMedia,在 768px 以下以及减少动态效果偏好开启时移除固定和滚动同步效果。
  • 字体加载完成后,以及布局发生任何变化后,调用 ScrollTrigger.refresh()。
4. Lenis(平滑滚动)

Lenis 通过插值处理滚轮输入,让滚动关联动画感觉连贯。它适用于营销页面,不适用于其他场景:

  • 减少动态效果偏好开启时禁用。在触屏设备上禁用(原生惯性滚动效果更好)。在任何拥有独立滚动条的区域内禁用(设置 data-lenis-prevent)。
  • 持续时间设为 1.1–1.3,easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t))。
  • 让 Lenis 驱动 GSAP 的 ticker(lenis.on("scroll", ScrollTrigger.update)),确保两者同步。
  • 锚点应通过 lenis.scrollTo(el, { offset: -header }) 滚动,而不是使用原生 scrollIntoView。
  • 模态框和菜单打开时调用 lenis.stop()。

文本揭示效果

按行或按词拆分文本,绝不按字符拆分,除非文本很短(例如单词徽标)。字符逐个显示会产生打字机效果,很快就会显得过时。

  • 按行:将 translateY(100%) 放在 overflow: hidden 包装元素内,错开 80ms,使用 700ms 的 ease-out-expo。这种经典效果至今仍是最佳选择。
  • 按词:透明度 + translateY(6px) + blur(6px→0),错开 30ms。
  • 只播放一次。首次进入视口时播放。之后,文本就只是文本。
  • 父元素的 aria-label 保存完整字符串;拆分后的 span 设置 aria-hidden。没有 JS 时,文本应以普通形式显示。
  • 窗口尺寸改变时重新拆分;在一种宽度下拆分的文本换到另一种宽度时,换行会出错。GSAP SplitText 会处理此问题;手动拆分则必须监听窗口尺寸变化。

Canvas 和 WebGL

适用时机

着色器背景、能响应指针移动的 3D 对象、粒子场、产品模型。如果用 CSS 渐变和噪声 SVG 就能实现,那就用它们。

如何做
  • 设备像素比最高为 2,大型画布设为 1.5。Retina 3× 会让像素数变成 4 倍,却没有可见提升。
  • 离屏时暂停:使用 IntersectionObserver,并在 document.hidden 时暂停。隐藏的画布仍在消耗 GPU,这是笔记本发烫最常见的原因。
  • 使用 ResizeObserver 调整尺寸,并进行防抖;只重置一次绘图缓冲区,而不是每帧都重置。
  • 页面只保留一个动画循环。多个 requestAnimationFrame 循环会互相争用。
  • 延迟导入库和场景。先渲染主视觉区的文本;准备就绪后,画布在 400ms 时淡入。主视觉区空白地等着 three.js 加载,是不合格的。
  • 卸载时释放几何体、材质、纹理和渲染器。在 SPA 中,路由切换时发生内存泄漏很常见。
  • 指针响应应经过缓动:每帧将目标值以 0.08–0.12 的比例插值过去。直接进行 1:1 跟踪会显得很机械。
  • 备用方案:使用颜色和视觉分量相近的静态图像或 CSS 渐变,在 WebGL 不可用、启用减少动态效果,或设备性能较低时启用(可将 navigator.hardwareConcurrency < 4 和 deviceMemory < 4 作为粗略判断条件)。
将着色器作为材质

用于背景的片元着色器比 3D 场景更省资源,而且往往效果更好:缓慢变化的渐变噪声、抖动光晕、颗粒效果。代码控制在 30 行以内,用时间和指针 uniform 驱动动画,并降低对比度,确保上方的文本清晰可读。抖动(有序抖动或蓝噪声)可以隐藏深色渐变中的色带,并增加质感。

3D

使用 Three.js 或 React Three Fiber。模型使用压缩的 glTF(Draco 或 Meshopt),大小控制在 2MB 以内,并使用与最终轮廓相符的 <Suspense> 回退内容。环境光使用小型 HDRI。除非阴影是效果重点,否则关闭阴影。后期处理最多使用一个通道,也可以完全不用。

加载策略

  1. HTML 包含所有文本,并为首屏图片指定尺寸。首次绘制时即可见。
  2. 加载字体(两个字重,预加载)。
  3. 布局稳定。此时记录 LCP。
  4. 加载滚动库和观察器。
  5. 画布、WebGL、模型:延迟加载,在浏览器空闲后淡入。

即使第 5 步失败或被跳过,页面也应完整可用。这就是检验标准。

减少动态效果与不启用 JS

在 prefers-reduced-motion: reduce 时:

  • 不使用 Lenis。不使用固定定位。不使用逐帧同步动画。不启用画布动画(静态画面可以)。
  • 不运行显现动画;内容保持可见。
  • 视频不自动播放。

不启用 JavaScript 时:

  • 显现动画隐藏的所有内容都应可见(html:not(.js) [data-reveal] { opacity: 1 })。
  • 页面从上到下正常阅读,场景预留的位置不应出现空白。

页面会被关掉的迹象

迹象修复方法
滚动被劫持;滚轮手感不对仅在营销页面使用 Lenis;触屏设备上关闭,或完全不用
固定定位的区块超过 300vh精简场景;缩短固定定位时长
文本只有在脚本拆分后才存在将文本放在 HTML 中;拆分只是增强效果
画布离屏后仍在运行使用 IntersectionObserver 暂停
全屏画布的 DPR 为 3限制为 2
three.js 加载完成前主视觉区一片空白先显示文本;画布淡入
视差效果达到 30%控制在 10% 以下,或完全不用
段落逐字显现改为逐行显现
仪表板上使用特效删除特效

目录中的资源

  • GSAP 和 ScrollTrigger、SplitText——这些配方所需的时间轴工具。
  • Lenis——平滑滚动,但请注意上述限制。
  • Three.js、React Three Fiber——用于网页 3D。
  • Codrops——关于滚动、WebGL 和转场效果的实验性教程。
  • Maxime Heckel——由实际开发并发布这些效果的人讲解着色器和 WebGL。
  • Godly、Awwwards——复制效果前,先研究它的用途。
  • 更多资源见 stealth.pm/build。

评论

支持 Markdown