Skip to main content

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  // 显示绿线(开始)和红线(结束)

一个完整的生活场景

假设你在做一个「产品介绍页」:

  1. 触发器:页面中的一张产品图(.product-img)。
  2. 触发规则:当图片滚动到屏幕中间时(start: "center center"),开始播放动画。
  3. 动画内容:图片旋转 + 文字渐显。
  4. 效果控制:用户滚动越快,动画播放越快(scrub: true)。
  5. 固定元素:播放动画时,固定底部购买按钮不动(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 // 吸附动画时长
}
}

startend

定义动画触发和结束的滚动位置

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))