You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Vanilla JS复刻GSAP ScrollTrigger滚动驱动动画效果

复刻GSAP ScrollTrigger的滚动驱动动画效果

需求描述

现有一个基于requestAnimationFrame的循环函数,通过scroll事件监听scrollY值,控制图片从left: 0移动至left: 100%;图片的父元素设置了min-height: 100vh。

需要实现:

  • 父元素高度持续扩展至超过100vh,直到图片的left值达到100%
  • 动画完成后,父元素停止扩展,随图片一同向上滚动
  • 不能使用position: sticky,要让用户感觉下方DOM元素被「固定」,直到图片动画完成才进入视野

核心问题:如何设置父div的高度,使得滚动到该div底部时,子元素的动画恰好完成?

基础代码示例

<div class="parent">
    <img src="image.jpg" alt="">
</div>

核心思路

要实现该效果,关键是计算出动画完成所需的滚动距离,然后将父元素高度设置为「视口高度 + 动画所需滚动距离」。这样用户从进入父元素到滚到底部的过程,刚好对应图片完成整个位移动画,之后父元素随页面正常滚动,下方内容进入视野。

具体实现步骤

  1. 计算动画核心参数

    • 确定图片从left:0到left:100%的总位移量:即父元素宽度减去图片自身宽度(避免图片超出父元素)
    • 设定滚动驱动速率:比如每滚动1px,图片移动0.3px(数值越小,完成动画需要的滚动距离越长,可按需调整)
  2. 动态设置父元素高度

    • 根据总位移量和滚动速率,算出完成动画需要的滚动距离:总位移量 / 滚动速率
    • 父元素最终高度 = 100vh + 滚动距离
  3. 滚动监听与动画更新

    • 监听scroll事件,计算当前滚动位置相对于父元素的动画进度(0-1区间)
    • 根据进度更新图片的left值,确保动画仅在父元素的滚动范围内执行

完整代码实现

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .parent {
            min-height: 100vh;
            position: relative;
            overflow: hidden;
            background: #f0f0f0;
        }
        .parent img {
            position: absolute;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
            width: 200px;
            height: auto;
        }
        .content-below {
            height: 100vh;
            background: #333;
            color: #fff;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 2rem;
        }
    </style>
</head>
<body>
    <div class="parent">
        <img src="https://picsum.photos/200/300" alt="示例图片">
    </div>
    <div class="content-below">下方内容,动画完成后才会显示</div>

    <script>
        const parent = document.querySelector('.parent');
        const img = parent.querySelector('img');
        
        // 动画参数配置
        const scrollRate = 0.3; // 滚动驱动速率,按需调整
        const parentWidth = parent.offsetWidth;
        const totalAnimationDistance = parentWidth - img.offsetWidth;
        const requiredScrollDistance = totalAnimationDistance / scrollRate;
        
        // 设置父元素高度
        parent.style.height = `${window.innerHeight + requiredScrollDistance}px`;
        
        // 更新动画进度
        function updateAnimation() {
            const parentTop = parent.getBoundingClientRect().top + window.scrollY;
            // 计算滚动进度,限制在0-1区间
            const scrollProgress = Math.min(1, Math.max(0, (window.scrollY - parentTop) / requiredScrollDistance));
            img.style.left = `${scrollProgress * totalAnimationDistance}px`;
        }
        
        // 滚动监听优化
        let ticking = false;
        window.addEventListener('scroll', () => {
            if (!ticking) {
                window.requestAnimationFrame(() => {
                    updateAnimation();
                    ticking = false;
                });
                ticking = true;
            }
        });
        
        // 窗口 resize 适配
        window.addEventListener('resize', () => {
            const newParentWidth = parent.offsetWidth;
            const newTotalDistance = newParentWidth - img.offsetWidth;
            const newScrollDistance = newTotalDistance / scrollRate;
            parent.style.height = `${window.innerHeight + newScrollDistance}px`;
            updateAnimation();
        });
    </script>
</body>
</html>

关键细节说明

  • 滚动进度控制:通过scrollY和父元素的offsetTop计算动画进度,确保进度始终在0-1之间,避免图片超出父元素范围
  • 窗口适配:监听窗口resize事件,重新计算动画参数,保证窗口大小改变时动画效果依然正确
  • 性能优化:用requestAnimationFrame包裹滚动回调,避免频繁触发导致页面卡顿

内容的提问来源于stack exchange,提问作者Mr.Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:10:25