关于 gsap
面向 Web 动效开发者的 GSAP 技能,讲解时间轴、滚动触发、错列动画和 React 集成。内容还涵盖常见实现陷阱与性能注意事项。
主要功能
- 01时间轴动画编排
- 02ScrollTrigger 滚动动画
- 03错列与分布式动画
- 04React useGSAP 集成
- 05动画实现陷阱说明
适用场景
- 01制作连续的多元素动画
- 02构建滚动驱动的页面效果
- 03在 React 中管理动画清理
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ athevon/ genjutsu --skill gsap安装后在 Claude Code 中输入/gsap确认已加载。
详细介绍
版本敏感。 以下每个 API 名称、SDK 门槛和浏览器支持声明均已于 2026-09-08 对照一手来源核实。核实依据和时间见
_jutsu/VERSIONS.md。如果该日期已久远,请在依据版本号采取行动前重新核实。
GSAP - 动画引擎
GSAP 3.15(于 2026 年 4 月 13 日发布)。自 3.13 起,整个库——包括所有曾经的 Club 插件(SplitText、MorphSVG、DrawSVG、ScrollSmoother、InertiaPlugin、MotionPathHelper、CustomEase 等)——均包含在公开的
gsapnpm 包中,并且免费,包含商业用途,遵循 GreenSock Standard「无需付费」许可。没有 Club 付费墙。 GreenSock 还发布了官方 Agent 技能(MIT,8 项技能:core、timeline、scrolltrigger、plugins、utils、react、performance、frameworks):https://github.com/greensock/gsap-skills ——值得与此子技能一同安装。
何时使用 GSAP
| 标准 | CSS 过渡 | Framer Motion | GSAP |
|---|---|---|---|
| 悬停 / 简单切换 | 是 | 是 | 杀鸡用牛刀 |
| 序列时间轴 | 否 | 有限 | 是 |
| 滚动驱动 | scroll-timeline | 有限 | ScrollTrigger |
| 复杂交错 | 否 | 基础 | Distribution |
| 移动端性能(60fps) | 良好 | 一般 | 极佳 |
| 文本拆分 | 否 | 否 | SplitText |
| SVG 变形 / 绘制 | 否 | 否 | MorphSVG |
| 包体积顾虑 | 0kb | ~30kb | ~25kb + 插件 |
规则:如果动画需要时间轴、与滚动联动或分布式交错,请使用 GSAP。否则优先使用 CSS。
设置
// Always register plugins at the top level
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(ScrollTrigger, SplitText);
React:使用 @gsap/react 包中的 useGSAP(),而不是 useEffect + 手动清理。
import { useGSAP } from "@gsap/react";
useGSAP(() => {
gsap.to(".box", { x: 200 });
}, { scope: containerRef }); // auto-cleanup, auto-revert
核心模式
使用 defaults{} 避免重复
const tl = gsap.timeline({
defaults: { duration: 0.8, ease: "power2.out" },
});
tl.to(".a", { y: -20 })
.to(".b", { y: -20 }, "<0.1")
.to(".c", { y: -20 }, "<0.1");
使用 fromTo 实现全面控制
gsap.fromTo(".card", { y: 40, opacity: 0 }, { y: 0, opacity: 1, stagger: 0.15 });
使用分布实现交错
gsap.to(".grid-item", {
scale: 0,
stagger: {
each: 0.05,
from: "center", // "start" | "end" | "center" | "edges" | "random" | index
grid: "auto", // auto-detects the grid
axis: "x", // "x" | "y" | null (both)
},
});
ScrollTrigger 模式
基本固定 + Scrub
gsap.to(".panel", {
x: "-300%",
ease: "none",
scrollTrigger: {
trigger: ".container",
pin: true,
scrub: 1,
end: () => "+=" + document.querySelector(".container").scrollWidth,
},
});
使用 Batch 批量显示
ScrollTrigger.batch(".card", {
onEnter: (elements) => gsap.to(elements, { opacity: 1, y: 0, stagger: 0.1 }),
start: "top 85%",
});
使用 containerAnimation 实现水平滚动
const scrollTween = gsap.to(".panels", {
x: () => -(document.querySelector(".panels").scrollWidth - window.innerWidth),
ease: "none",
scrollTrigger: { trigger: ".wrapper", pin: true, scrub: 1 },
});
// Animate elements INSIDE the horizontal scroll
gsap.to(".panel-content", {
scale: 1.2,
scrollTrigger: {
trigger: ".panel-content",
containerAnimation: scrollTween, // linked to horizontal scroll
start: "left center",
end: "right center",
scrub: true,
},
});
切勿这样做 - 关键错误
1. 在 containerAnimation 上使用 Ease
// BAD - ease breaks the scroll mapping
scrollTrigger: { containerAnimation: scrollTween, scrub: 1, ease: "power2.out" }
// GOOD - always ease: "none" on the parent tween
const scrollTween = gsap.to(".panels", { x: ..., ease: "none", scrollTrigger: { scrub: 1 } });
2. 在时间轴中的子补间上使用 ScrollTrigger
// BAD - ScrollTrigger ignores child tweens of a timeline that has its own ScrollTrigger
const tl = gsap.timeline({ scrollTrigger: { trigger: ".section" } });
tl.to(".box", { x: 100, scrollTrigger: { trigger: ".box" } }); // IGNORE
// GOOD - one ScrollTrigger per timeline OR standalone tweens
gsap.to(".box", { x: 100, scrollTrigger: { trigger: ".box" } }); // tween standalone
3. 在 onUpdate 中调用 setState
// BAD - setState 60x/s = re-render hell
scrollTrigger: { onUpdate: (self) => setProgress(self.progress) }
// GOOD - mutate a ref or DOM element directly
const progressRef = useRef(0);
scrollTrigger: { onUpdate: (self) => { progressRef.current = self.progress; } }
// Or better: gsap.quickSetter to mutate the DOM without React
4. 在时间轴中的 from() 上使用 immediateRender
// BAD - from() has immediateRender: true by default, breaks sequencing
tl.to(".box", { x: 100 });
tl.from(".box", { y: 50 }); // visually jumps to the start
// GOOD - disable immediateRender when from() follows another tween
tl.to(".box", { x: 100 });
tl.from(".box", { y: 50, immediateRender: false });
5. 为非 transform 属性添加动画
// BAD - width/height/top/left trigger layout reflow
gsap.to(".box", { width: 200, height: 200 });
// GOOD - use transforms (GPU-accelerated, composited)
gsap.to(".box", { scaleX: 1.5, scaleY: 1.5 });
// If actual size needed: use Flip plugin for layout transition
参考资料
references/core.md- 完整的 gsap.to/from/fromTo/set API 和选项references/timeline.md- 时间轴、位置参数、嵌套references/scrolltrigger.md- 完整的 ScrollTrigger 参考references/plugins.md- SplitText、Flip、MorphSVG、DrawSVG、MotionPath、Observer
评论
支持 Markdown