
本文详解如何使用 gsap + scrolltrigger 实现精准可控的滚动淡出效果,重点解决 opacity 未完全归零、时序错位、scrub 行为误解等常见问题,并提供可复用的 vue/html 完整方案。
本文详解如何使用 gsap + scrolltrigger 实现精准可控的滚动淡出效果,重点解决 opacity 未完全归零、时序错位、scrub 行为误解等常见问题,并提供可复用的 vue/html 完整方案。
在构建沉浸式滚动叙事页面时,标题区域常需承担「横向滑动 + 纵向淡出」双重动效——即先沿 X 轴平移展示长标题,随后在继续滚动中渐隐退出视口。GSAP 的 ScrollTrigger 插件是实现该效果的行业首选,但初学者极易陷入两个典型误区:混淆 fromTo() 的起止逻辑 与 误判 scrub 对 opacity 动画的适用性。
你原始代码中的关键问题在于:
const scrollOut = gsap.fromTo('.titles', {
opacity: 1
}, {
opacity: 0
});这段看似合理,实则存在根本性偏差:gsap.fromTo() 默认以 时间轴起点为 from 状态、终点为 to 状态,而当 scrub: 0(非连续同步)时,ScrollTrigger 仅会在 start → end 区间内“播放”一次该动画——但若 end 位置过早(如 '140%'),动画可能尚未执行到 opacity: 0 就已终止;更严重的是,fromTo 在 scrub: 0 下不具备进度映射能力,无法随滚动实时插值。
✅ 正确解法是:统一使用 gsap.to() + scrub: true,并显式定义 start 和 end 对应的属性值,让 ScrollTrigger 直接控制 opacity 的线性过渡:
// ✅ 推荐写法:单个 scrubbed 动画,全程受滚动驱动
ScrollTrigger.create({
trigger: '.titleWrapper',
start: 'top top', // 标题顶部对齐视口顶部时开始
end: () => `+=${Math.abs(getScrollAmount()) + window.innerHeight}`, // 延伸足够距离确保完全淡出
scrub: true, // 启用滚动同步(非 0 或 1,推荐 true 实现平滑插值)
animation: gsap.to('.titles', {
opacity: 0,
ease: 'none' // 保持线性衰减,符合滚动物理直觉
})
});同时,横向滚动动画也应与淡出共用同一 ScrollTrigger 实例,避免时序竞争:
// ✅ 合并为一个 ScrollTrigger,同时控制 x 和 opacity
const titlesWidth = document.querySelector('.titles').scrollWidth;
const maxX = -(titlesWidth - window.innerWidth);
ScrollTrigger.create({
trigger: '.titleWrapper',
start: 'top top',
end: () => `+=${Math.abs(maxX) + window.innerHeight}`,
pin: true,
scrub: true,
animation: gsap.timeline()
.to('.titles', { x: maxX, duration: 1, ease: 'none' }) // 横向滚动(占前半程)
.to('.titles', { opacity: 0, duration: 1, ease: 'none' }, '<') // 淡出(与上一动画同步开始,'<': at same time)
});? 关键注意事项:
-
scrub: true(而非scrub: 1)能启用高精度滚动插值,避免卡顿或跳变; - 避免
fromTo()在scrub: 0场景下使用——它适用于一次性触发动画,而非滚动映射; -
end值务必足够大(如+=${maxX + window.innerHeight}),确保滚动到底部时opacity真正抵达0; - 若需更精细控制(如淡出起始点延后),可用
start: 'bottom center'或start: 'center center'调整触发锚点; - 在 Vue 中,建议将 ScrollTrigger 实例挂载至
onMounted并在onBeforeUnmount中调用.kill()清理,防止内存泄漏。
最终效果:标题先平滑横移展露全貌,随后在持续滚动中匀速淡出至完全透明——无残留、无闪烁、响应精准。GSAP 的强大,正在于它把复杂的时间轴逻辑,浓缩为几行语义清晰的声明式配置。

















