关于 gsap-scrolltrigger
gsap-scrolltrigger 是介绍 GSAP ScrollTrigger 的技能资料,面向制作滚动驱动动画与交互的开发者。内容涵盖触发器配置、动画同步及常见滚动效果。
主要功能
- 01配置滚动触发位置与动作
- 02将动画进度绑定到滚动
- 03固定页面区块并设置吸附点
- 04创建视差与横向滚动效果
- 05批量处理滚动动画
- 06使用回调跟踪滚动状态
适用场景
- 01制作滚动进入时的元素显现
- 02构建固定区块的横向滚动页面
- 03添加滚动进度条或视差背景
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bbeierle12/ skill-mcp-claude --skill gsap-scrolltrigger安装后在 Claude Code 中输入/gsap-scrolltrigger确认已加载。
附带文件_meta.json
详细介绍
GSAP ScrollTrigger
由滚动驱动的动画和交互。
快速入门
npm install gsap
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
gsap.to('.box', {
x: 500,
scrollTrigger: {
trigger: '.box',
start: 'top center',
end: 'bottom center',
scrub: true
}
});
核心概念
基本 ScrollTrigger
gsap.to('.element', {
x: 200,
scrollTrigger: {
trigger: '.element', // Element that triggers the animation
start: 'top center', // When trigger hits viewport center
end: 'bottom center', // When trigger leaves viewport center
toggleActions: 'play pause resume reset'
}
});
起始/结束位置
// Format: "trigger-position viewport-position"
start: 'top center' // Trigger's top hits viewport center
start: 'top 80%' // Trigger's top hits 80% down viewport
start: 'center center' // Trigger's center hits viewport center
start: 'bottom top' // Trigger's bottom hits viewport top
start: 'top top+=100' // Trigger's top hits 100px below viewport top
位置参考
| 值 | 描述 |
|---|---|
top | 顶部边缘 |
center | 中心 |
bottom | 底部边缘 |
80% | 距顶部 80% |
+=100 | 加 100 像素 |
-=50 | 减 50 像素 |
Scrub 动画
基本 Scrub
// Animation progress tied to scroll position
gsap.to('.progress-bar', {
scaleX: 1,
scrollTrigger: {
trigger: '.content',
start: 'top top',
end: 'bottom bottom',
scrub: true // Directly linked to scroll
}
});
平滑 Scrub
gsap.to('.element', {
x: 500,
scrollTrigger: {
trigger: '.section',
scrub: 1, // 1 second smoothing
// scrub: 0.5 // 0.5 second smoothing
// scrub: 2 // 2 second smoothing (laggy feel)
}
});
使用时间轴的 Scrub
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.container',
start: 'top top',
end: '+=3000', // Scroll distance
scrub: 1,
pin: true
}
});
tl.to('.step1', { opacity: 1 })
.to('.step2', { opacity: 1 })
.to('.step3', { opacity: 1 });
固定
基本固定
ScrollTrigger.create({
trigger: '.panel',
start: 'top top',
end: '+=500', // Pin for 500px of scroll
pin: true
});
带动画的固定
gsap.to('.content', {
x: '-200%',
ease: 'none',
scrollTrigger: {
trigger: '.horizontal-section',
start: 'top top',
end: () => '+=' + document.querySelector('.horizontal-section').offsetWidth,
pin: true,
scrub: 1
}
});
固定间距
ScrollTrigger.create({
trigger: '.section',
pin: true,
pinSpacing: true, // Default: adds space for pinned duration
// pinSpacing: false // No extra space (content overlaps)
// pinSpacing: '500px' // Custom spacing
});
切换操作
操作语法
// Format: "onEnter onLeave onEnterBack onLeaveBack"
toggleActions: 'play pause resume reset'
// Common combinations:
toggleActions: 'play none none none' // Play once
toggleActions: 'play reverse play reverse' // Toggle direction
toggleActions: 'restart none none none' // Restart each time
toggleActions: 'play complete reverse reset'
操作值
| 操作 | 效果 |
|---|---|
play | 向前播放 |
pause | 暂停 |
resume | 从暂停处继续 |
reverse | 向后播放 |
restart | 从头重新开始 |
reset | 重置到起点(不播放动画) |
complete | 跳到末尾 |
none | 不执行任何操作 |
吸附点
基本吸附
ScrollTrigger.create({
trigger: '.sections',
start: 'top top',
end: 'bottom bottom',
snap: 1 / 4 // Snap to quarters
});
吸附到标签
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.container',
scrub: 1,
snap: {
snapTo: 'labels',
duration: 0.5,
ease: 'power2.inOut'
}
}
});
tl.addLabel('intro')
.to('.a', { opacity: 1 })
.addLabel('middle')
.to('.b', { opacity: 1 })
.addLabel('end');
吸附配置
snap: {
snapTo: [0, 0.25, 0.5, 0.75, 1], // Snap to specific points
duration: { min: 0.2, max: 0.6 }, // Snap duration range
delay: 0, // Delay before snap
ease: 'power1.inOut', // Snap easing
directional: true // Snap in scroll direction
}
回调
ScrollTrigger 回调
ScrollTrigger.create({
trigger: '.section',
onEnter: () => console.log('Entered'),
onLeave: () => console.log('Left'),
onEnterBack: () => console.log('Entered from bottom'),
onLeaveBack: () => console.log('Left going up'),
onUpdate: (self) => console.log('Progress:', self.progress),
onToggle: (self) => console.log('Active:', self.isActive),
onRefresh: () => console.log('Refreshed')
});
基于进度的更新
ScrollTrigger.create({
trigger: '.section',
start: 'top bottom',
end: 'bottom top',
onUpdate: (self) => {
// self.progress: 0 to 1
// self.direction: 1 (down) or -1 (up)
// self.velocity: scroll speed
updateElement(self.progress);
}
});
视差效果
基本视差
// Background moves slower than scroll
gsap.to('.background', {
yPercent: -50,
ease: 'none',
scrollTrigger: {
trigger: '.section',
scrub: true
}
});
// Foreground moves faster
gsap.to('.foreground', {
yPercent: 50,
ease: 'none',
scrollTrigger: {
trigger: '.section',
scrub: true
}
});
多层视差
const layers = [
{ selector: '.layer-1', speed: -20 },
{ selector: '.layer-2', speed: -40 },
{ selector: '.layer-3', speed: -60 },
{ selector: '.layer-4', speed: -80 }
];
layers.forEach(layer => {
gsap.to(layer.selector, {
yPercent: layer.speed,
ease: 'none',
scrollTrigger: {
trigger: '.parallax-section',
start: 'top bottom',
end: 'bottom top',
scrub: true
}
});
});
水平滚动
水平区段
const sections = gsap.utils.toArray('.panel');
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: 'none',
scrollTrigger: {
trigger: '.horizontal-container',
pin: true,
scrub: 1,
snap: 1 / (sections.length - 1),
end: () => '+=' + document.querySelector('.horizontal-container').offsetWidth
}
});
标记(开发)
ScrollTrigger.create({
trigger: '.section',
start: 'top center',
end: 'bottom center',
markers: true, // Show visual markers
// markers: { startColor: 'green', endColor: 'red', fontSize: '12px' }
});
批量动画
滚动时交错显示
ScrollTrigger.batch('.card', {
onEnter: (elements) => {
gsap.from(elements, {
opacity: 0,
y: 50,
stagger: 0.1,
duration: 0.5
});
},
start: 'top 85%'
});
批量配置
ScrollTrigger.batch('.item', {
interval: 0.1, // Time between batches
batchMax: 3, // Max items per batch
onEnter: batch => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.1 }),
onLeave: batch => gsap.to(batch, { opacity: 0, y: 20 }),
onEnterBack: batch => gsap.to(batch, { opacity: 1, y: 0 }),
onLeaveBack: batch => gsap.to(batch, { opacity: 0, y: -20 })
});
常见模式
滚动时显示
gsap.utils.toArray('.reveal').forEach(elem => {
gsap.from(elem, {
opacity: 0,
y: 50,
duration: 0.8,
scrollTrigger: {
trigger: elem,
start: 'top 80%',
toggleActions: 'play none none none'
}
});
});
进度指示器
gsap.to('.progress-bar', {
scaleX: 1,
transformOrigin: 'left center',
ease: 'none',
scrollTrigger: {
trigger: 'body',
start: 'top top',
end: 'bottom bottom',
scrub: 0.3
}
});
粘性页眉变换
ScrollTrigger.create({
start: 'top -80',
onUpdate: (self) => {
if (self.direction === 1) {
gsap.to('.header', { y: -80, duration: 0.3 });
} else {
gsap.to('.header', { y: 0, duration: 0.3 });
}
}
});
时间坍缩模式
倒计时滚动显示
// Reveal countdown sections as user scrolls
const sections = ['days', 'hours', 'minutes', 'seconds'];
sections.forEach((section, i) => {
gsap.from(`.countdown-${section}`, {
opacity: 0,
scale: 0.8,
y: 50,
duration: 0.8,
ease: 'power3.out',
scrollTrigger: {
trigger: `.countdown-${section}`,
start: 'top 80%',
toggleActions: 'play none none none'
}
});
});
基于滚动的时间膨胀效果
gsap.timeline({
scrollTrigger: {
trigger: '.time-section',
start: 'top center',
end: 'bottom center',
scrub: 1
}
})
.to('.time-digit', {
textShadow: '0 0 50px #00F5FF, 0 0 100px #00F5FF',
scale: 1.1
})
.to('.particles', {
opacity: 1,
filter: 'blur(0px)'
}, '<');
性能提示
// Disable on mobile if needed
ScrollTrigger.matchMedia({
'(min-width: 768px)': function() {
// Desktop animations
},
'(max-width: 767px)': function() {
// Simpler mobile animations
}
});
// Refresh on resize
ScrollTrigger.refresh();
// Kill all ScrollTriggers
ScrollTrigger.killAll();
// Kill specific trigger
const st = ScrollTrigger.create({ ... });
st.kill();
参考
- 动画基础请参见
gsap-fundamentals - 时间轴组合请参见
gsap-sequencing - ScrollTrigger 的 React 集成请参见
gsap-react
评论
支持 Markdown