
本文详解如何使用 GSAP + ScrollTrigger 实现标题横向滚动后精准淡出的交互动画,重点解析 scrub、start/end 触发点、fromTo 动画范围与 opacity 插值逻辑,并给出可复用的 Vue/HTML 完整实现方案。
本文详解如何使用 gsap + scrolltrigger 实现标题横向滚动后精准淡出的交互动画,重点解析 `scrub`、`start/end` 触发点、`fromto` 动画范围与 opacity 插值逻辑,并给出可复用的 vue/html 完整实现方案。
在构建现代网页动效时,「滚动即动画」已成为提升沉浸感的核心手段。GSAP 的 ScrollTrigger 插件正是为此而生——它将时间轴(Timeline)与滚动位置解耦绑定,使动画完全受用户滚动行为驱动。但正如你在实践中遇到的问题:看似简单的“先横移、再淡出”,却常因触发时机错位、动画范围不匹配或插值边界未显式定义,导致效果失真(如只淡出至 50% 而非完全透明)。
关键问题在于:gsap.fromTo(..., {opacity: 1}, {opacity: 0}) 默认将动画映射到整个 ScrollTrigger 的 start → end 区间,但若未明确指定该区间内 opacity 的变化起止位置,GSAP 会按线性均分处理,极易造成终点未达 0。
✅ 正确解法是 显式锚定淡出动画的起始与结束滚动位置,并利用 scrub: true 实现平滑跟随,而非依赖默认区间分配:
// ✅ 推荐写法:精准控制淡出阶段的滚动范围
ScrollTrigger.create({
trigger: '.titleWrapper',
start: 'bottom 80%', // 淡出开始:当 .titleWrapper 底部到达视口 80% 高度时启动
end: 'bottom 20%', // 淡出结束:滚动至底部到达视口 20% 高度时完成(即留出缓冲区)
scrub: true, // 启用滚动跟随,动画值随滚动实时插值
animation: gsap.fromTo(
'.titles',
{ opacity: 1, ease: 'none' },
{ opacity: 0, ease: 'none' }
),
markers: false
})同时,横向滚动部分需确保 x 位移与 ScrollTrigger 的 end 值严格同步。你原代码中 getScrollAmount() 返回负值,而 end: +=${...} 是叠加模式,易引发计算歧义。更健壮的方式是:
const titles = document.querySelector('.titles');
const scrollWidth = titles.scrollWidth - window.innerWidth;
ScrollTrigger.create({
trigger: '.titleWrapper',
start: 'top top',
end: () => `+=${scrollWidth}`, // 显式使用像素值,避免符号混淆
pin: true,
scrub: 1,
animation: gsap.to('.titles', {
x: -scrollWidth, // 向左滚动完整内容宽度
duration: 1,
ease: 'none'
}),
invalidateOnRefresh: true
});? 重要注意事项:
-
scrub: true(或scrub: 1)是实现滚动跟随动画的必要条件,禁用scrub将退化为一次性播放; -
opacity动画必须与x动画分离为两个独立的 ScrollTrigger,否则pin会干扰透明度过渡; - 在 Vue 环境中,建议将
ScrollTrigger实例存入onBeforeUnmount清理钩子,防止内存泄漏:onBeforeUnmount(() => { scrollXTrigger?.kill(); fadeTrigger?.kill(); })
最后,关于你提到的 “opacity: -2.5” ——这实为误操作(opacity 合法值域为 0–1)。真正生效的是你调整了 end 位置使动画区间拉长,从而让 opacity 有足够滚动距离从 1 平滑降至 0。GSAP 的强大之处,正在于它把「动画逻辑」和「滚动语义」清晰分离:你定义 什么动(tween),ScrollTrigger 定义 何时动(trigger + range),二者协同,方得精准。
至此,一个兼具性能、可控性与专业级表现力的滚动驱动标题动画便已就绪。后续可叠加 y 位移、缩放或颜色渐变,全部复用同一套 ScrollTrigger 控制范式。


















