Back

使用 GSAP 的 ScrollTrigger 动画让您的 UI 焕发生机

使用 GSAP 的 ScrollTrigger 动画让您的 UI 焕发生机

基于滚动的动画可以将静态网站转变为引人入胜的交互式体验。虽然 CSS 动画对于基本效果很有用,但创建复杂的滚动驱动动画需要更强大的工具。GSAP 的 ScrollTrigger 插件正是这样的工具——让您能够创建由滚动位置触发的精美、高性能动画。

在本指南中,您将学习如何实现能够自然响应用户滚动的 ScrollTrigger 动画,并提供可在您的项目中立即使用的实用示例。

核心要点

  • ScrollTrigger 将动画与滚动位置连接,创造交互式体验
  • 使用 scrub 将动画进度直接与滚动位置绑定
  • 固定元素以创建高级的基于滚动的效果
  • 配置 startend 来精确控制动画触发时机
  • 在开发过程中使用 markers 来可视化触发点

什么是 ScrollTrigger,为什么要使用它?

ScrollTrigger 是一个 GSAP 插件,它将动画与滚动位置连接起来。与仅在元素进入视口时触发动画的基本”滚动触发”库不同,ScrollTrigger 提供了精确控制:

  • 基于滚动位置的动画开始和结束时机
  • 用户滚动时动画的进度(擦除效果)
  • 在用户滚动经过时固定元素
  • 创建复杂的基于滚动的交互

结果如何?动画感觉与用户滚动相连,而不仅仅是在触发时播放。

ScrollTrigger 入门

首先,让我们设置基础结构:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ScrollTrigger Demo</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: Arial, sans-serif;
        }
        
        section {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        
        .spacer {
            height: 100vh;
        }
        
        .box {
            width: 200px;
            height: 200px;
            background-color: #3498db;
            border-radius: 8px;
        }
    </style>
</head>
<body>
    <div class="spacer"></div>
    
    <section>
        <div class="box"></div>
    </section>
    
    <div class="spacer"></div>
    
    <!-- GSAP and ScrollTrigger -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
    
    <script>
        // Register the plugin
        gsap.registerPlugin(ScrollTrigger);
        
        // Your animations will go here
    </script>
</body>
</html>

基础 ScrollTrigger 动画

让我们从一个简单的动画开始,当元素进入视口时触发:

gsap.to(".box", {
    scrollTrigger: ".box", // 触发动画的元素
    x: 300, // 向右移动 300px
    rotation: 360, // 旋转 360 度
    duration: 1.5, // 动画持续时间
    ease: "power2.out" // 缓动函数
});

这段代码在盒子进入视口时移动并旋转它。但这只是触及表面。

理解 ScrollTrigger 配置

要释放 ScrollTrigger 的全部潜力,我们需要理解其配置选项:

gsap.to(".box", {
    scrollTrigger: {
        trigger: ".box", // 触发动画的元素
        start: "top center", // 当盒子顶部到达视口中心时开始
        end: "bottom center", // 当盒子底部到达视口中心时结束
        toggleActions: "play pause reverse reset", // 进入、离开、重新进入、重新离开时的动作
        markers: true, // 显示调试标记(生产环境中移除)
    },
    x: 300,
    rotation: 360,
    duration: 2
});

startend 属性定义动画何时激活和停用。格式为 "[触发元素位置] [视口位置]"

toggleActions 控制动画在四个关键时刻的行为:

  1. 进入触发区域时
  2. 离开触发区域时
  3. 向上滚动时重新进入触发区域
  4. 向上滚动时离开触发区域

选项包括:playpauseresumereverserestartresetcompletenone

使用 Scrub 创建滚动驱动动画

真正的魔法发生在 scrub 属性上,它将动画进度直接与滚动位置绑定:

gsap.to(".box", {
    scrollTrigger: {
        trigger: ".box",
        start: "top center",
        end: "bottom center",
        scrub: true, // 将动画进度与滚动位置链接
        markers: true
    },
    x: 300,
    rotation: 360,
    backgroundColor: "#e74c3c"
});

使用 scrub: true,动画会随着用户滚动而进行,甚至在向上滚动时反向播放。为了更平滑的动画,使用数值如 scrub: 0.5 来添加轻微延迟。

在滚动过程中固定元素

ScrollTrigger 最强大的功能之一是在用户滚动时将元素固定在位:

gsap.to(".box", {
    scrollTrigger: {
        trigger: ".box",
        start: "center center",
        end: "+=300", // 在开始位置后 300px 处结束
        pin: true, // 在动画期间固定盒子
        scrub: 1,
        markers: true
    },
    x: 300,
    rotation: 360,
    scale: 1.5,
    backgroundColor: "#9b59b6"
});

这会在动画播放时将盒子固定在位,创造类似视差的效果。end: "+=300" 意味着动画在超过开始点 300 像素后结束。

创建显现动画

让我们为文本或图像创建一个实用的显现动画:

<div class="spacer"></div>

<section class="reveal-section">
    <div class="reveal-container">
        <h1 class="reveal-text">滚动驱动动画</h1>
        <p class="reveal-text">使用 GSAP ScrollTrigger 创建引人入胜的用户体验</p>
    </div>
</section>

<div class="spacer"></div>
.reveal-section {
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.reveal-container {
    max-width: 800px;
    text-align: center;
    overflow: hidden;
}

.reveal-text {
    opacity: 0;
    transform: translateY(50px);
}
// 显现动画
gsap.utils.toArray('.reveal-text').forEach(text => {
    gsap.to(text, {
        scrollTrigger: {
            trigger: text,
            start: "top 80%", // 当文本顶部距离视口顶部 80% 时开始
            toggleActions: "play none none none"
        },
        y: 0,
        opacity: 1,
        duration: 1,
        ease: "power2.out"
    });
});

这创建了一个干净的显现效果,当每个文本元素进入视口时触发。

创建视差效果

视差效果为您的网站增加深度。以下是创建方法:

<div class="parallax-container">
    <div class="parallax-bg"></div>
    <div class="parallax-content">
        <h1>视差效果</h1>
    </div>
</div>
.parallax-container {
    height: 100vh;
    position: relative;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
}

.parallax-bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 120%; /* 移动所需的额外高度 */
    background-image: url('your-background-image.jpg');
    background-size: cover;
    background-position: center;
}

.parallax-content {
    position: relative;
    z-index: 1;
    color: white;
    text-align: center;
}
// 视差效果
gsap.to(".parallax-bg", {
    scrollTrigger: {
        trigger: ".parallax-container",
        start: "top bottom",
        end: "bottom top",
        scrub: true
    },
    y: -100, // 滚动时背景向上移动 100px
    ease: "none"
});

这创建了一个简单的视差效果,背景以不同于前景的速度移动。

水平滚动部分

创建水平滚动部分是另一个令人印象深刻的效果:

<div class="spacer"></div>

<section class="horizontal-scroll">
    <div class="horizontal-container">
        <div class="panel">面板 1</div>
        <div class="panel">面板 2</div>
        <div class="panel">面板 3</div>
        <div class="panel">面板 4</div>
    </div>
</section>

<div class="spacer"></div>
.horizontal-scroll {
    overflow: hidden;
    height: 100vh;
}

.horizontal-container {
    display: flex;
    width: 400%; /* 100% * 面板数量 */
    height: 100%;
}

.panel {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 2rem;
}

.panel:nth-child(1) { background-color: #3498db; }
.panel:nth-child(2) { background-color: #2ecc71; }
.panel:nth-child(3) { background-color: #e74c3c; }
.panel:nth-child(4) { background-color: #9b59b6; }
// 水平滚动
gsap.to(".horizontal-container", {
    scrollTrigger: {
        trigger: ".horizontal-scroll",
        start: "top top",
        end: "+=3000", // 滚动距离
        pin: true,
        scrub: 1,
    },
    x: () => -(document.querySelector(".horizontal-container").offsetWidth - window.innerWidth),
    ease: "none"
});

这创建了一个在用户垂直滚动时水平滚动的部分。

性能优化技巧

如果实现不当,ScrollTrigger 动画可能会影响性能。以下是一些技巧:

  1. 谨慎使用 will-change:仅应用于实际动画的元素
  2. 避免动画布局属性:尽可能坚持使用 transform 和 opacity
  3. 批处理相似动画:使用 gsap.utils.toArray() 并循环遍历元素
  4. 在不需要时销毁 ScrollTriggers:对于单页应用程序使用 scrollTrigger.kill()
  5. 减少标记使用:在生产环境中移除 markers: true

常见问题故障排除

动画开始得太早/太晚

如果您的动画在意外时间触发,请检查您的 startend 值。使用 markers: true 来可视化触发点。

动画卡顿

为了更平滑的动画,使用 scrub: 0.5 或更高值而不是 scrub: true 来添加轻微延迟。

移动端兼容性问题

移动浏览器处理滚动事件的方式不同。在移动设备上彻底测试,并考虑使用 ScrollTrigger.matchMedia() 为不同屏幕尺寸创建不同的动画。

结论

使用这些技术,您可以创建自然响应用户交互的滚动动画,在不让用户感到overwhelmed的情况下增强您的 UI。从简单效果开始,随着您对 ScrollTrigger 功能的熟悉逐渐融入更高级的技术。

常见问题

可以,但您需要在组件挂载/卸载时正确设置和清理 ScrollTrigger 实例。

ScrollTrigger 是为 GSAP 设计的,但您可以使用其回调函数来触发其他库。

使用百分比进行定位,并在窗口大小调整时使用 ScrollTrigger.refresh() 刷新 ScrollTrigger。

基本功能是免费的,但一些高级功能需要 GreenSock Club 会员资格。

使用 markers: true 来可视化触发点,并在回调函数中使用 console.log 来跟踪进度。

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers