scrollTrigger
核心概念
- 核心思想:将页面滚动行为视为一个「时间轴」,当用户滚动页面时,就像拖动进度条控制动画播放。
- 类比:类似视频播放器的进度条,滚动到不同位置触发不同动画效果。
核心概念分解
1. 触发器(Trigger)
是什么:页面上的一个「感应区」(比如一个方块、图片)。
作用:当这个区域进入/离开屏幕时,触发动画。
示例:
trigger: ".box" // 当".box"元素进入屏幕时,触发动画
2. 滚动容器(Scroller)
是什么:监听哪个容器的滚动事件(默认是浏览器窗口)。
场景:处理嵌套滚动(比如一个 div 内部滚动)。
scroller: "#sidebar" // 监听侧边栏的滚动条
3. 触发位置(Start/End)
- 是什么:定义何时开始和结束动画,通过「元素位置」和「视口位置」计算。
- 通俗解释:
start: "top center"
→ 当元素顶部(.box
)碰到视口中间线时,触发动画。end: "bottom top"
→ 当元素底部碰到视口顶部时,结束动画。- 类似「门框感应器」:元素碰到特定位置线,触发开关。
https://miro.medium.com/v2/resize:fit:1400/1*J8kq5J3LrZ0M2vqV7oB7xQ.png
4. 联动动画(Scrub)
- 是什么:滚动时让动画「实时跟随」或「延迟跟随」。
- 效果:
scrub: true
→ 滚动时动画实时更新(如视差效果)。scrub: 1
→ 滚动后动画延迟1秒完成(如平滑过渡)。
5. 固定元素(Pin)
是什么:在滚动时「钉住」某个元素不动(比如固定标题)。
示例:
pin: ".header" // 滚动到触发区域时,固定头部不动
6. 视觉辅助(Markers)
是什么:在页面上显示调试线(开发时用)。
作用:直观看到触发区域的起止位置。
markers: true // 显示绿线(开始)和红线(结束)
一个完整的生活场景
假设你在做一个「产品介绍页」:
- 触发器:页面中的一张产品图(
.product-img
)。 - 触发规则:当图片滚动到屏幕中间时(
start: "center center"
),开始播放动画。 - 动画内容:图片旋转 + 文字渐显。
- 效果控制:用户滚动越快,动画播放越快(
scrub: true
)。 - 固定元素:播放动画时,固定底部购买按钮不动(
pin: ".buy-btn"
)。
为什么需要 ScrollTrigger?
- 交互增强:将静态滚动变成动态体验(如苹果官网的滚动效果)。
- 精准控制:将动画与用户行为(滚动)绑定,替代传统的「时间轴动画」。
- 性能优化:自动处理复杂的位置计算和事件监听。
代码示例(极简版)
gsap.to(".box", {
x: 500,
scrollTrigger: {
trigger: ".box",
start: "top center",
end: "bottom top",
scrub: 1,
markers: true,
onEnter: () => console.log("开始表演!")
}
});
使用示例
// 通过时间线创建
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".container", // 触发元素
start: "top center", // 开始位置:触发元素顶部 碰到视口中心
end: "bottom top", // 结束位置:触发元素底部 碰到视口顶部
scrub: 2, // 滚动时动画跟随(1秒延迟)
markers: true // 显示调试标记
}
});
// 通过普通api
gsap.to(trackWarp.current, {
x: () => {
const res = (DEFAULT_SUB_COLOR.length - 1) * window.innerWidth;
console.log("总偏移: ", res);
return `-${res}`;
},
scrollTrigger: {
trigger: trackWarp.current,
start: "center center",
end: () => "+=" + (trackWarp.current.scrollWidth - window.innerWidth),
scrub: 1,
pin: true,
invalidateOnRefresh: true,
id: "id-one",
},
});
配置详解
scrollTrigger: {
// 核心配置
trigger: ".container", // [类型: string | Element] 触发元素,默认null,支持选择器字符串或元素实例(兼容React/Vue的ref对象)
scroller: "body", // [类型: string | Element] 滚动容器,默认窗口,场景:嵌套滚动容器中定位
// 触发位置(支持6种格式:像素值/百分比/相对位置组合)
start: "top center", // [类型: string | number | Function]
// 格式:"[触发器位置] [视口位置]",例:"top 80%"/"+=100 center"/100
end: "bottom top", // [类型: string | number | Function]
// 格式同上,特殊值:"+=500"表示start后滚动500px
// 动画控制
scrub: 1, // [类型: boolean | number] 滚动联动动画,默认false
// true=实时跟随,数字=延迟秒数(平滑过渡)
pin: ".section", // [类型: boolean | string | Element] 固定元素,默认false
// true=固定trigger元素,字符串=固定指定元素
// 视觉辅助
markers: { // [类型: boolean | object] 调试标记,默认false
startColor: "green", // 自定义标记颜色/尺寸
endColor: "red",
fontSize: "16px"
},
toggleClass: { // [类型: string | object] 类名控制,默认null
targets: ".box", // 需要添加class的目标元素
className: "active" // 添加的class名称
},
// 高级定位
anticipatePin: 1, // [类型: number] 预判固定距离(秒),默认0.1
// 优化快速滚动时的固定定位
horizontal: true, // [类型: boolean] 水平滚动模式,默认false
// 场景:横向滚动网页设计
// 回调函数(self参数携带进度/方向等状态)
onEnter: self => {}, // 正向滚动进入触发区域时
onLeave: self => {}, // 正向滚动离开触发区域时
onEnterBack: self => {}, // 反向滚动进入触发区域时
onLeaveBack: self => {}, // 反向滚动离开触发区域时
onUpdate: self => { // 滚动时持续触发
console.log(self.progress.toFixed(2)); // 当前进度0-1
},
onToggle: ({ isActive }) => { // 激活状态变化时
console.log(isActive ? "激活" : "未激活");
},
// 性能优化
fastScrollEnd: true, // [类型: boolean] 快速滚动优化,默认true
// 跳过中间动画步骤提升性能
invalidateOnRefresh: true, // [类型: boolean] 窗口resize时重新计算,默认false
// 场景:响应式布局需要动态更新位置
// 高级控制(补充常用配置)
once: true, // [类型: boolean] 仅触发一次,默认false
toggleActions: "play none none none", // [类型: string] 滚动行为控制
// 格式:"进入 离开 进入反向 离开反向"
snap: { // [类型: number | string | Array] 吸附效果
snapTo: "labels", // 吸附到时间轴标签
duration: 0.3 // 吸附动画时长
}
}
start
、end
定义动画触发和结束的滚动位置
start: "top center", // 格式: [触发元素位置] [视口位置]
end: "+=500", // 相对于开始位置增加500px滚动距离
位置参数格式:
值 | 示例 | 说明 |
---|---|---|
视口位置 | "top" , "center" , "bottom" | 视口顶部/中心/底部 |
触发元素位置 | "top" , "center" , "bottom" | 触发元素自身的参考位置 |
像素值 | "100" , "+=300" | 绝对或相对像素值 |
百分比 | "80%" | 相对于触发元素高度 |
scrub
滚动与动画进度同步方式
scrub: true // 实时同步(无延迟)
scrub: 2 // 平滑跟随(2秒延迟)
scrub: false // 仅在经过位置时触发一次
pin
在动画期间固定元素
pin: ".header" // 固定元素直到动画结束
pin: true // 固定 trigger 元素本身
markers
显示调试标记
markers: true // 显示所有标记
markers: { startColor: "red", endColor: "blue" } // 自定义标记颜色
toggleClass
在触发时添加/移除类名
toggleClass: { targets: ".box", className: "active" }
toggleActions
控制动画播放行为
toggleActions: "play pause resume reset"
// 格式: [进入时] [离开时] [重新进入时] [完全离开时]
回调函数onEnter
/ onLeave
/ onUpdate
onEnter: () => console.log("进入触发区域"),
onUpdate: (self) => console.log("进度:", self.progress.toFixed(2))