GSAP 动画库快速学习指南

87 阅读11分钟

GSAP 动画库快速学习指南

📚 什么是GSAP?

GSAP (GreenSock Animation Platform) 是一个强大的JavaScript动画库,它让开发者能够轻松创建高性能、复杂的动画效果。无论是简单的元素动画,还是复杂的交互和视差效果,GSAP都能胜任。

为什么选择GSAP?

  • 🚀 高性能:比CSS动画和其他JS动画库更流畅
  • 🔄 跨浏览器兼容:解决各种浏览器兼容性问题
  • 🛠️ 灵活强大:可以动画几乎任何属性(不限于CSS属性)
  • 📊 精确控制:精确到0.01毫秒的时间轴控制
  • 🧩 丰富的插件生态:ScrollTrigger、MotionPath等扩展功能

🌟 GSAP基础知识

1. 核心概念

GSAP有三个主要的动画方法:

// 从当前状态到指定状态(最常用)
gsap.to(".selector", {
  x: 100,               // 向右移动100px
  duration: 1,          // 动画持续1秒
  ease: "power2.out"    // 缓动函数
});

// 从指定状态到当前状态
gsap.from(".selector", {
  opacity: 0,           // 从透明开始
  y: 50,                // 从下方50px开始
  duration: 1
});

// 从一个状态到另一个状态
gsap.fromTo(".selector", 
  { opacity: 0, y: 50 },           // 起始状态
  { opacity: 1, y: 0, duration: 1 } // 结束状态
);

2. 基本属性

GSAP可以动画的常用属性:

属性说明示例
x, y, z2D/3D位置x: 100
rotation旋转(度)rotation: 360
scale缩放scale: 1.5
opacity透明度opacity: 0
backgroundColor背景色backgroundColor: "#ff0000"
width, height尺寸width: "100%"

3. 控制动画

// 创建动画并保存引用
const animation = gsap.to(".box", {duration: 1, x: 100});

// 控制动画
animation.pause();    // 暂停
animation.play();     // 播放
animation.reverse();  // 反向播放
animation.restart();  // 重新开始
animation.progress(0.5); // 跳转到50%进度

🎯 GSAP常用功能

1. 时间轴(Timeline)

时间轴是GSAP的强大功能,可以精确排序多个动画:

// 创建时间轴
const tl = gsap.timeline({
  defaults: { duration: 1 },  // 所有子动画的默认设置
  paused: true,               // 创建时不自动播放
  repeat: 2                   // 重复次数
});

// 添加动画到时间轴
tl.to(".box1", { x: 100 })
  .to(".box2", { y: 50 }, "<") // "<"表示与前一个动画同时开始
  .to(".box3", { scale: 1.5 }, "+=0.5") // 前一个动画结束后延迟0.5秒
  .to(".box4", { opacity: 0 }, 2); // 在时间轴2秒处开始

2. ScrollTrigger插件

让动画与页面滚动关联:

// 注册插件
gsap.registerPlugin(ScrollTrigger);

// 基本用法
gsap.to(".element", {
  x: 300,
  scrollTrigger: {
    trigger: ".element",    // 触发元素
    start: "top center",    // 开始位置(元素顶部到达视口中心)
    end: "bottom center",   // 结束位置
    scrub: true,            // 动画跟随滚动进度
    toggleActions: "play pause reverse reset", // 进入、离开等行为
    markers: true           // 调试标记(开发时使用)
  }
});

3. 实用工具

// 设置初始状态
gsap.set(".element", { autoAlpha: 0, y: 20 });

// 批量处理多个元素
gsap.utils.toArray(".boxes").forEach((box, i) => {
  gsap.to(box, { x: 100, delay: i * 0.1 });
});

// 随机值
gsap.to(".element", {
  x: "random(-100, 100)",  // 随机值
  rotation: () => Math.random() * 360 // 使用函数返回随机值
});

🎭 GSAP视差效果实现

视差效果是指不同元素以不同的速度移动,从而产生深度感。以下是几种常见的视差效果实现方法:

1. 基础滚动视差

// 背景视差
gsap.to(".background", {
  y: 200,
  scrollTrigger: {
    trigger: ".section",
    start: "top top",
    end: "bottom top",
    scrub: true  // 平滑跟随滚动
  }
});

// 内容视差 (移动速度不同)
gsap.to(".content", {
  y: -100,  // 注意方向与背景相反
  scrollTrigger: {
    trigger: ".section",
    start: "top top",
    end: "bottom top",
    scrub: true
  }
});

2. 多层视差效果

关键在于不同层使用不同的移动速度:

// 远景层(移动慢)
gsap.to(".layer-bg", {
  y: 50,
  scrollTrigger: { trigger: ".section", scrub: 1 }
});

// 中景层(中等速度)
gsap.to(".layer-mid", {
  y: 100, 
  scrollTrigger: { trigger: ".section", scrub: 1 }
});

// 前景层(移动快)
gsap.to(".layer-fg", {
  y: 150,
  scrollTrigger: { trigger: ".section", scrub: 1 }
});

3. 鼠标跟随视差

使用鼠标位置创建视差效果:

document.addEventListener("mousemove", (e) => {
  // 计算鼠标位置相对于窗口中心的偏移
  const centerX = window.innerWidth / 2;
  const centerY = window.innerHeight / 2;
  const offsetX = (e.clientX - centerX) / centerX;
  const offsetY = (e.clientY - centerY) / centerY;
  
  // 不同元素应用不同的移动速度
  gsap.to(".layer1", {
    x: offsetX * 20,  // 慢速移动
    y: offsetY * 20,
    duration: 1
  });
  
  gsap.to(".layer2", {
    x: offsetX * 40,  // 中速移动
    y: offsetY * 40,
    duration: 1
  });
  
  gsap.to(".layer3", {
    x: offsetX * 60,  // 快速移动
    y: offsetY * 60,
    duration: 1
  });
});

4. 视差卡片效果

当滚动到卡片时,可以使用不同的动画参数:

gsap.utils.toArray(".card").forEach((card, i) => {
  // 每个卡片有不同的动画参数
  gsap.to(card, {
    y: i * 40,           // 不同的移动距离
    rotation: i % 2 ? 5 : -5, // 交替旋转方向
    scrollTrigger: {
      trigger: card,
      start: "top bottom",
      end: "bottom top",
      scrub: 1
    }
  });
});

💼 实际案例解析

示例1:滚动触发的元素淡入效果

// 元素从底部淡入
gsap.utils.toArray(".fade-in").forEach(element => {
  gsap.from(element, {
    opacity: 0,
    y: 50,
    duration: 1,
    scrollTrigger: {
      trigger: element,
      start: "top 80%", // 当元素顶部达到视口80%位置时
      toggleActions: "play none none none"
    }
  });
});

示例2:视差图片画廊

const images = gsap.utils.toArray(".gallery img");

images.forEach((image, i) => {
  // 创建交错的动画效果
  gsap.to(image, {
    y: (i % 2 === 0) ? -100 : 100, // 交替上下移动
    scrollTrigger: {
      trigger: ".gallery",
      start: "top bottom",
      end: "bottom top",
      scrub: true
    }
  });
});

示例3:文字分段动画

// 将文本拆分为字符
const splitText = new SplitText(".heading", {type: "chars"});
const chars = splitText.chars;

// 创建交错动画
gsap.from(chars, {
  opacity: 0,
  y: 50,
  stagger: 0.05, // 每个字符间隔0.05秒
  duration: 0.8,
  ease: "back.out"
});

一个比较完整示例

可以直接拷贝到html文件中双击运行

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GSAP 视差效果示例</title>
    <!-- 引入 GSAP 核心库 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
    <!-- 引入 ScrollTrigger 插件,用于滚动触发动画 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: Arial, sans-serif;
            overflow-x: hidden;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }

        .container {
            width: 100%;
            min-height: 100vh;
        }

        /* 示例1:基础视差区域 */
        .parallax-section {
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            overflow: hidden;
        }

        .parallax-bg {
            position: absolute;
            width: 100%;
            height: 120%;
            background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
            z-index: 0;
        }

        .parallax-content {
            position: relative;
            z-index: 1;
            text-align: center;
            color: white;
        }

        .parallax-content h1 {
            font-size: 4rem;
            margin-bottom: 20px;
        }

        /* 示例2:多层视差卡片 */
        .cards-section {
            padding: 100px 20px;
            min-height: 100vh;
        }
        .cards-section1 {
            padding: 100px 20px;
            min-height: 100vh;
        }

        .card {
            width: 300px;
            height: 400px;
            margin: 50px auto;
            background: white;
            border-radius: 20px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 2rem;
            font-weight: bold;
            color: #667eea;
        }

        /* 示例3:图片视差层 */
        .image-parallax-section {
            height: 100vh;
            position: relative;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .parallax-layer {
            position: absolute;
            width: 200px;
            height: 200px;
            border-radius: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 3rem;
        }

        .layer-1 { background: #ff6b6b; top: 20%; left: 10%; }
        .layer-2 { background: #4ecdc4; top: 50%; left: 60%; }
        .layer-3 { background: #45b7d1; top: 70%; left: 30%; }

        /* 示例4:文字视差 */
        .text-parallax-section {
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #1a1a2e;
            position: relative;
            overflow: hidden;
        }

        .text-parallax-wrapper {
            text-align: center;
        }

        .parallax-text {
            font-size: 5rem;
            font-weight: bold;
            color: white;
            margin: 20px 0;
            opacity: 0;
        }

        /* 示例5:鼠标跟随视差 */
        .mouse-parallax-section {
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            position: relative;
            overflow: hidden;
        }

        .mouse-parallax-item {
            position: absolute;
            width: 100px;
            height: 100px;
            border-radius: 50%;
            background: rgba(255,255,255,0.3);
        }

        .mouse-parallax-item:nth-child(1) { width: 150px; height: 150px; }
        .mouse-parallax-item:nth-child(2) { width: 100px; height: 100px; }
        .mouse-parallax-item:nth-child(3) { width: 80px; height: 80px; }

        .section-title {
            position: absolute;
            top: 50px;
            left: 50%;
            transform: translateX(-50%);
            color: white;
            font-size: 2rem;
            z-index: 10;
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- 示例1:基础背景视差效果 -->
        <section class="parallax-section">
            <h1 style="color: white;z-index: 111;">GSAP 视差效果</h1>
            <div class="parallax-bg" id="parallax-bg"></div>
            <div class="parallax-content" id="parallax-content">
                <h1>GSAP 视差效果</h1>
                <p>向下滚动查看更多示例</p>
            </div>
        </section>

        <!-- 示例2:卡片视差效果 -->
        <section class="cards-section">
            <div class="card card-1">卡片 1</div>
            <div class="card card-2">卡片 2</div>
            <div class="card card-3">卡片 3</div>
        </section>

         <!-- 示例2:卡片视差效果 -->
         <section class="cards-section1">
            <div class="card card-1">卡片 1</div>
            <div class="card card-2">卡片 2</div>
            <div class="card card-3">卡片 3</div>
        </section>

        <!-- 示例3:多层图片视差 -->
        <section class="image-parallax-section">
            <h2 class="section-title">多层视差效果</h2>
            <div class="parallax-layer layer-1">🌟</div>
            <div class="parallax-layer layer-2">🚀</div>
            <div class="parallax-layer layer-3">🎨</div>
        </section>

        <!-- 示例4:文字交错视差 -->
        <section class="text-parallax-section">
            <div class="text-parallax-wrapper">
                <div class="parallax-text text-1">欢迎</div>
                <div class="parallax-text text-2">学习</div>
                <div class="parallax-text text-3">GSAP</div>
            </div>
        </section>

        <!-- 示例5:鼠标跟随视差 -->
        <section class="mouse-parallax-section" id="mouse-section">
            <h2 class="section-title">移动鼠标查看效果</h2>
            <div class="mouse-parallax-item" data-speed="0.5"></div>
            <div class="mouse-parallax-item" data-speed="0.3"></div>
            <div class="mouse-parallax-item" data-speed="0.2"></div>
        </section>
    </div>

    <script>
        // 注册 ScrollTrigger 插件

        // ============================================================
        // 示例1:基础背景视差效果
        // 背景移动速度比内容慢,产生视差效果
        // ============================================================
        gsap.to("#parallax-bg", {
            // y 轴向下移动 200px
            y: 200,
            // 滚动触发器配置
            scrollTrigger: {
                trigger: ".parallax-section", // 触发元素
                start: "top top",              // 动画开始位置(元素顶部到达视口顶部时)
                end: "bottom top",             // 动画结束位置(元素底部到达视口顶部时)
                scrub: true,                   // 平滑跟随滚动(true 表示直接绑定滚动进度)
                // markers: true                // 开启此项可显示调试标记
            }
        });

        // 内容淡出效果
        gsap.to("#parallax-content", {
            opacity: 0,
            y: 100,
            scrollTrigger: {
                trigger: ".parallax-section",
                start: "top top",
                end: "bottom top",
                scrub: true // 平滑跟随滚动(true 表示直接绑定滚动进度)
            }
        });

        // ============================================================
        // 示例2:卡片交错视差动画
        // 每个卡片有不同的移动速度和旋转效果
        // ============================================================
        gsap.utils.toArray(".cards-section .card").forEach((card, index) => {
            // 根据索引设置不同的视差速度
            const speed = (index + 1) * 50;
            
            gsap.to(card, {
                y: speed,           // 向下移动
                rotation: 10,       // 旋转10度
                scrollTrigger: {
                    trigger: card,
                    start: "top bottom",  // 卡片顶部进入视口底部时开始
                    end: "bottom top",    // 卡片底部离开视口顶部时结束
                    scrub: 1,             // 平滑度为1(数字越大越平滑)
                }
            });

            // 入场动画:从左侧淡入
            gsap.from(card, {
                x: -200,           // 从左侧200px外
                opacity: 0,        // 透明度从0开始
                duration: 1,       // 动画持续1秒
                scrollTrigger: {
                    trigger: card,
                    start: "top 80%",  // 卡片顶部到达视口80%位置时触发
                    toggleActions: "play none none reverse"  // 进入播放,离开反转
                }
            });
        });

        gsap.utils.toArray(".cards-section1 .card").forEach((card, index) => {
            // 根据索引设置不同的视差速度
            const speed = (index + 1) * 50;
            
            gsap.to(card, {
                y: speed,           // 向下移动
                rotation: -10,       // 旋转10度
                scrollTrigger: {
                    trigger: card,
                    start: "top bottom",  // 卡片顶部进入视口底部时开始
                    end: "bottom top",    // 卡片底部离开视口顶部时结束
                    scrub: 1,             // 平滑度为1(数字越大越平滑)
                }
            });

            // 入场动画:从左侧淡入
            gsap.from(card, {
                x: 200,           // 从左侧200px外
                opacity: 0,        // 透明度从0开始
                duration: 1,       // 动画持续1秒
                scrollTrigger: {
                    trigger: card,
                    start: "top 80%",  // 卡片顶部到达视口80%位置时触发
                    toggleActions: "play none none reverse"  // 进入播放,离开反转
                }
            });
        });

        // ============================================================
        // 示例3:多层视差效果
        // 不同层有不同的移动速度,创造深度感
        // ============================================================
        gsap.to(".layer-1", {
            y: -150,              // 最快的层
            x: 100,
            scrollTrigger: {
                trigger: ".image-parallax-section",
                start: "top bottom",
                end: "bottom top",
                scrub: 1
            }
        });

        gsap.to(".layer-2", {
            y: -100,              // 中等速度
            x: -80,
            scrollTrigger: {
                trigger: ".image-parallax-section",
                start: "top bottom",
                end: "bottom top",
                scrub: 1
            }
        });

        gsap.to(".layer-3", {
            y: -50,               // 最慢的层
            x: 60,
            scrollTrigger: {
                trigger: ".image-parallax-section",
                start: "top bottom",
                end: "bottom top",
                scrub: 1
            }
        });

        // ============================================================
        // 示例4:文字交错视差效果
        // 文字按顺序出现,每个有不同的延迟和移动距离
        // ============================================================
        const textTimeline = gsap.timeline({
            scrollTrigger: {
                trigger: ".text-parallax-section",
                start: "top 60%",
                end: "bottom 60%",
                scrub: 1
            }
        });

        // 添加交错动画到时间轴
        textTimeline
            .to(".text-1", { opacity: 1, y: 0, duration: 0.5 })
            .to(".text-2", { opacity: 1, y: 0, duration: 0.5 }, "-=0.2")  // 提前0.2秒开始
            .to(".text-3", { opacity: 1, y: 0, duration: 0.5 }, "-=0.2");

        // 设置初始位置
        gsap.set(".parallax-text", { y: 100 });

        // ============================================================
        // 示例5:鼠标跟随视差效果
        // 鼠标移动时,元素根据speed属性以不同速度跟随
        // ============================================================
        const mouseSection = document.getElementById("mouse-section");
        const mouseItems = document.querySelectorAll(".mouse-parallax-item");

        mouseSection.addEventListener("mousemove", (e) => {
            // 获取鼠标相对于视口的位置
            const mouseX = e.clientX;
            const mouseY = e.clientY;
            
            // 获取视口中心点
            const centerX = window.innerWidth / 2;
            const centerY = window.innerHeight / 2;
            
            // 计算鼠标偏移量
            const offsetX = (mouseX - centerX) / centerX;
            const offsetY = (mouseY - centerY) / centerY;

            mouseItems.forEach((item) => {
                // 获取每个元素的速度属性
                const speed = parseFloat(item.getAttribute("data-speed"));
                
                // 根据速度计算移动距离
                const moveX = offsetX * 100 * speed;
                const moveY = offsetY * 100 * speed;

                // 使用 GSAP 动画移动元素
                gsap.to(item, {
                    x: moveX,
                    y: moveY,
                    duration: 1.5,     // 动画持续时间
                    ease: "power2.out" // 缓动函数
                });
            });
        });

        // 设置鼠标跟随元素的初始位置(随机分布)
        mouseItems.forEach((item, index) => {
            gsap.set(item, {
                x: Math.random() * window.innerWidth - 100,
                y: Math.random() * window.innerHeight - 100
            });
        });

        // ============================================================
        // 额外技巧:页面加载时的入场动画
        // ============================================================
        window.addEventListener("load", () => {
            gsap.from("#parallax-content h1", {
                scale: 0,              // 从0开始缩放
                rotation: 360,         // 旋转360度
                duration: 1.5,         // 持续1.5秒
                ease: "back.out(1.7)"  // 回弹缓动效果,  控制回弹的强度, 数值越大, 回弹越强烈
            });

            gsap.from("#parallax-content p", {
                opacity: 0,
                y: 50,
                duration: 1,
                delay: 0.5,           // 延迟0.5秒开始
                ease: "power2.out" // 缓动函数, 控制动画的速度变化, 数值越大, 速度越快
            });
        });
    </script>
</body>
</html>

🧠 GSAP学习策略

1. 学习路线

  1. 基础动画 - 掌握to, from, fromTo方法
  2. 时间轴 - 学习如何编排多个动画
  3. ScrollTrigger - 掌握滚动触发动画
  4. 高级功能 - 探索MotionPath, SplitText等插件
  5. 性能优化 - 学习如何创建高性能动画

2. 实践建议

  • 🔍 拆解喜欢的网站动画 - 查看优秀网站的源代码
  • 🧪 从简单开始 - 先实现简单动画,逐步添加复杂度
  • 📝 保持代码组织 - 使用时间轴组织复杂动画
  • 🐞 使用调试工具 - ScrollTrigger的markers功能
  • 🔄 频繁迭代 - 不断尝试不同参数观察效果

3. 常见陷阱

  • 🚫 过度动画 - 动画太多会分散注意力
  • ⚠️ 性能问题 - 注意移动设备上的性能
  • 🔍 兼容性 - 测试不同浏览器和设备
  • 🕰️ 时机控制 - 注意动画的开始和结束时机

📚 GSAP学习资源

官方资源