SuperAPI AI 工具集

gsap-scrolltrigger-pin

前端与建站

查看项目

更新于 10-16 05:16

技能介绍

用途

gsap-scrolltrigger-pin 是一个用于构建「固定式横向滚动 section」(pinned horizontal-scroll section)的技能。当用户滚动到某个 section 时,该 section 会固定在视口中,用户继续进行的纵向滚动会被 GSAP ScrollTrigger 读取,并转换为一个包含多张幻灯片的 track 的横向滑动。这是行业内常见的标准技术实现。

适用触发场景包括:页面需要「横向画廊」风格的 section(如案例展示、作品集、产品介绍),而用户仍像平常一样只用纵向滚轮操作。当用户提到「pin section」「横向滚动」「horizontal scroll section」「scroll-driven horizontal」「gsap scrolltrigger」或调用 /gsap-scrolltrigger-pin 时使用。

不适用范围:不需要 pin 的轻微滚动效果(应使用 scroll-effects),或为整页滚动增加顺滑感(应使用 lenis-smooth-scroll)。这两个技能不引入 GSAP 依赖。本技能仅适用于一个具体的固定 section。

心智模型

结构为:[data-hp-section] > .hp-pin(固定层)> [data-hp-track](应用 xPercent 补间与 scrub)> [data-hp-slide] × N。end 是一个函数,在每次 refresh() 时重新测量 track.scrollWidth;matchMedia 用于选择 GSAP 分支或 reduce-motion 分支(后者使用普通 CSS 横向滚动)。

输入与输出

输入:section 的幻灯片内容(必填,如案例展示/作品集/产品);是否允许引入外部库 GSAP(必填,若不允许则使用 assets/ 中的精简版,但仍必须使用 GSAP);项目 design.md(可选,若存在则据此调整颜色 token)。输出:项目中的 pin + 横向 track section(必填,可复制原始文件并保留署名注释,或改编 assets/);playwright-verify 验证证据(必填,确认固定时机正确、无横向溢出、resize 后仍正常)。

规则与能力

RULE-01(必须):GSAP 依赖为必需,缺少 GSAP + ScrollTrigger 插件时该技能无法运行。安装方式二选一:CDN(如 demo.html 所示)先加载 https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js 与 ScrollTrigger.min.js,再加载技能脚本;或使用 npm,npm install gsap,然后 import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger);。

RULE-02(必须):在 prefers-reduced-motion: reduce 下,GSAP 分支完全不初始化(无 ScrollTrigger、无 pin、无 scrub),由 CSS 将 .hp-pin 转为 overflow-x: auto 的普通横向滚动(scroll-snap-type: x mandatory)。该分支中不要添加任何 JS 动画。

RULE-03(必须):track 使用 xPercent 而非 x(像素)。xPercent 会依据 track 的实际宽度自适应,即使幻灯片内容尺寸变化也不需要手动重算像素偏移。

RULE-04(必须):使用 playwright-verify 验证:纵向滚动经过整个 section,断言固定时机正确(track 未走完幻灯片时视口不再继续纵向滚动),断言页面其余部分无横向溢出,测试修改视口尺寸后重新滚动,确保 ScrollTrigger.refresh() 已捕获新布局。

能力:读取原始版本(web/git)与技能 asset 及 design.md;向目标项目写入 HTML/CSS/JS;运行无头浏览器进行验证。

失败边界:缺少 GSAP + ScrollTrigger 且不允许添加依赖时视为 blocked(RULE-01),若需求实际不需要 pin,建议改用 scroll-effects/lenis-smooth-scroll。以 file:// 打开文件会导致行为异常,必须通过本地 HTTP 运行。验证断言为红(未固定、横向溢出、resize 崩溃)时视为 failed,修复后重新验证。

使用方式(主流程)

W01 判断:确认需要 pin + 横向滚动(而非 scroll-effects/lenis-smooth-scroll),不需要 pin 则改用其他技能。 W02 执行:打开原始运行链接,将原始 .html(含 _assets/)复制进项目,保留署名注释;若不允许引入外部库则走 B01。 W03 执行:仅修改内容、图片与颜色。 W04 确定性验证:通过 HTTP 运行页面,用 playwright-verify 验证 RULE-04;断言绿色即通过,红色则修复并重复 W04。

分支:B01 当项目不允许引入外部库时,使用 vanilla assets/ 精简版(参见 Reference — Assets)进行 ADAPT,但仍需 GSAP(RULE-01),随后回到 W04。B02 当 prefers-reduced-motion: reduce 时,不初始化 GSAP,改用普通 CSS 横向滚动(RULE-02),随后回到 W04。

验证与停止:W04 处进行确定性断言(固定时机正确、无横向溢出、resize 后重新滚动仍正确)。需要人工确认内容/颜色与项目匹配。断言绿色即停止;若循环超过 2 轮仍为红,则附带截图告知用户。

示例

正面示例:「做一个作品集横向滚动 section」→ 从 Rheinmir/uiux-asset 复制 horizontal-scroll-section-with-gsap-and-locomotive-scroll.html,替换图片与文字 → 用 playwright 纵向滚动验证:section 固定,track 滑动完所有幻灯片后才释放,无横向溢出。

边界/失败示例:使用 x: -2000(像素)而非 xPercent → 修改视口尺寸后 track 偏移、最后一张幻灯片缺失 → 违反 RULE-03,改为 xPercent: -100 * (slideCount - 1) 后重新验证 resize。

参考 — 原始版本(优先使用,复制原文件,不要重写)

作者原始代码(CodePen 公开 = MIT)位于外部仓库 Rheinmir/uiux-asset,可运行的画廊示例:https://rheinmir.github.io/uiux-asset/scroll-effects/ 。流程:打开运行链接查看实际效果 → 将原始 .html(以及其引用的 _assets/ 目录)复制进项目 → 保留首行署名注释 → 仅修改内容/图片/颜色。通过本地 HTTP 运行,不要用 file://。如需完整离线版本可执行 git clone --depth 1 https://github.com/Rheinmir/uiux-asset。

原始 Pen(作者):

  • Horizontal Scroll Section with GSAP and Locomotive Scroll — cameronknight
  • Smooth Scroll Stacking Accordion — supah
  • Infinite Horizontal Scroll with Progress Tracking — haptichash
  • Pinned Split-Screen Mask Reveal — gridmorphic
  • Scroll-Driven SVG Map Editorial Gallery — knyttneve

本技能中的 assets/ 仅为自行编写的 vanilla 精简版,仅在项目不允许引入外部库时使用;默认使用上述原始版本。

参考 — Assets

assets/demo.html + assets/gsap-scrolltrigger-pin.css + assets/gsap-scrolltrigger-pin.js — 阅读后 ADAPT(替换幻灯片内容,若项目有 design.md 则按其颜色 token 调整)。直接用浏览器打开 demo.html 可查看实际运行机制(asset 通过 CDN 加载 GSAP)。

参考 — 机制

标记结构:[data-hp-section] > .hp-pin > [data-hp-track] > [data-hp-slide] × N — track 为 flex-row,每个幻灯片 flex: 0 0 100vw,总宽度 = N × 100vw(由布局自然得出,无需手算)。

ScrollTrigger 固定 .hp-pin(pin: true, start: "top top"),scrub: 1 将动画进度锁定到滚动位置——不是按时间播放的动画。

动画为 gsap.to(track, { xPercent: -100 * (slideCount - 1) }) — slideCount 从 track.querySelectorAll('[data-hp-slide]').length 读取,代码中不硬编码幻灯片数量。

end 是一个函数:() => "+=" + (track.scrollWidth - window.innerWidth) — 每次 ScrollTrigger.refresh() 运行时重新计算(依据当时 DOM 中 track.scrollWidth 的真实值),而非固定数值。

ScrollTrigger.matchMedia() 包裹整个初始化:当视口断点变化或 prefers-reduced-motion 变化时,GSAP 自动回退旧分支并重新运行匹配分支——这是「安然度过」resize 的标准做法,而非自行编写 resize 监听器。

window.addEventListener('load', () => ScrollTrigger.refresh()) 用于捕获图片/字体加载完成后 track 真实 scrollWidth 变化的情况。