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

如何用GSAP ScrollTrigger实现滚动时多Div底部固定并逐段展示内容?

问题描述

需要使用GSAP的ScrollTrigger插件实现以下垂直滚动动画效果:

  • 首次滚动时,5个标题全部可见
  • 继续滚动,第1个标题向上滚动,对应段落按高度逐步显示,其余4个标题固定在窗口底部
  • 第1个标题和段落完全显示后,第2个标题向上滚动并显示对应段落,以此类推

条件要求:

  • 每个Div包含1个标题和1个段落
  • 默认状态下标题可见,段落隐藏

注意事项:第5个Div的标题必须固定在底部,直到第4个Div的动画完成后才可滚动


解决方案

实现逻辑

  1. 通过position: sticky将列表容器固定在视口内,让标题默认排列在视口底部
  2. 为前4个列表项创建独立的ScrollTrigger时间线,控制标题上移、段落展开,以及序号和线条的颜色变化
  3. 最后一个列表项默认用固定定位锁定在底部,待前4个动画完成后,再切换为相对定位并执行自身的展开动画
  4. 每个动画阶段占用100vh的滚动范围,确保滚动节奏清晰

完整代码

<section style="background:black; height: 100vh"></section>
<div class="provider-benefit">
    <div class="container-xl">
        <div class="row justify-content-xl-end">
            <div class="col-12">
                <div class="provider-benefit-list" id="pb_list">
                    <div class="list-item"> <span class="list-item-no">1</span> <span class="list-item-line"></span>
                        <div class="list-item-wrapper">
                            <div class="list-item-header">
                                <h3 class="list-item-title">Lorem Ipsum 1</h3> </div>
                            <div class="list-item-body">
                                <p class="list-item-content">1. Lorem ipsum is placeholder text commonly used in the graphic.</p>
                            </div>
                        </div>
                    </div>
                    <div class="list-item"> <span class="list-item-no">2</span> <span class="list-item-line"></span>
                        <div class="list-item-wrapper">
                            <div class="list-item-header">
                                <h3 class="list-item-title">Lorem Ipsum 2</h3> </div>
                            <div class="list-item-body">
                                <p class="list-item-content">2. Lorem ipsum is placeholder text</p>
                            </div>
                        </div>
                    </div>
                    <div class="list-item"> <span class="list-item-no">3</span> <span class="list-item-line"></span>
                        <div class="list-item-wrapper">
                            <div class="list-item-header">
                                <h3 class="list-item-title">Lorem Ipsum 3</h3> </div>
                            <div class="list-item-body">
                                <p class="list-item-content">3. Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups</p>
                            </div>
                        </div>
                    </div>
                    <div class="list-item"> <span class="list-item-no">4</span> <span class="list-item-line"></span>
                        <div class="list-item-wrapper">
                            <div class="list-item-header">
                                <h3 class="list-item-title">Lorem Ipsum 4</h3> </div>
                            <div class="list-item-body">
                                <p class="list-item-content">4. Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups</p>
                            </div>
                        </div>
                    </div>
                    <div class="list-item"> <span class="list-item-no">5</span> <span class="list-item-line"></span>
                        <div class="list-item-wrapper">
                            <div class="list-item-header">
                                <h3 class="list-item-title">Lorem Ipsum 5</h3> </div>
                            <div class="list-item-body">
                                <p class="list-item-content">5. Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups</p>
                            </div>
                        </div>
                    </div>
                    <!-- list items end -->
                </div>
            </div>
        </div>
    </div>
</div>
<section style="background:black; height: 100vh" id=""></section>

<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js" defer="defer"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js" defer="defer"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
    gsap.registerPlugin(ScrollTrigger);
    
    const listItems = document.querySelectorAll('.list-item');
    const lastItem = listItems[listItems.length - 1];
    let totalScrollOffset = 0;

    // 处理前4个列表项的滚动动画
    listItems.forEach((item, index) => {
        if (index === 4) return;
        
        const header = item.querySelector('.list-item-header');
        const body = item.querySelector('.list-item-body');
        const no = item.querySelector('.list-item-no');
        const line = item.querySelector('.list-item-line');
        const bodyHeight = body.scrollHeight;

        const tl = gsap.timeline({
            scrollTrigger: {
                trigger: '.provider-benefit-list',
                start: `top+=${totalScrollOffset}vh top`,
                end: `top+=${totalScrollOffset + 100}vh top`,
                scrub: true,
                ease: 'linear'
            }
        });

        tl.to(header, { y: -bodyHeight, duration: 0.5 })
          .to(body, { height: bodyHeight, opacity: 1, duration: 0.5 }, 0)
          .to(no, { backgroundColor: "#04B7A9", duration: 0.3 }, 0)
          .to(line, { backgroundColor: "#04B7A9", duration: 0.3 }, 0);

        totalScrollOffset += 100;
    });

    // 释放最后一个固定的列表项
    gsap.to(lastItem, {
        position: 'relative',
        bottom: 'auto',
        left: 'auto',
        right: 'auto',
        scrollTrigger: {
            trigger: '.provider-benefit-list',
            start: `top+=${totalScrollOffset}vh top`,
            end: `top+=${totalScrollOffset + 100}vh top`,
            scrub: true,
            ease: 'linear'
        }
    });

    // 最后一个列表项的内容展开动画
    const lastHeader = lastItem.querySelector('.list-item-header');
    const lastBody = lastItem.querySelector('.list-item-body');
    const lastNo = lastItem.querySelector('.list-item-no');
    const lastLine = lastItem.querySelector('.list-item-line');
    const lastBodyHeight = lastBody.scrollHeight;

    const lastTl = gsap.timeline({
        scrollTrigger: {
            trigger: '.provider-benefit-list',
            start: `top+=${totalScrollOffset}vh top`,
            end: `top+=${totalScrollOffset + 100}vh top`,
            scrub: true,
            ease: 'linear'
        }
    });

    lastTl.to(lastHeader, { y: -lastBodyHeight, duration: 0.5 })
          .to(lastBody, { height: lastBodyHeight, opacity: 1, duration: 0.5 }, 0)
          .to(lastNo, { backgroundColor: "#04B7A9", duration: 0.3 }, 0)
          .to(lastLine, { backgroundColor: "#04B7A9", duration: 0.3 }, 0);
});
</script>

<style>
.provider-benefit {
    position: relative;
    background-repeat: no-repeat;
    background-size: 43%;
    background-position: -15.5% 51.7%;
    counter-reset: listnumber;
    min-height: 500vh;
}

.provider-benefit-img {
    max-width: 600px;
    width: 100%;
}

.provider-benefit-list {
    padding-left: var(--size_30_half);
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

.provider-benefit .list-item {
    position: relative;
    padding-left: 60px;
    padding-right: var(--size_10);
    margin-bottom: var(--size_20);
    overflow: hidden;
}

.provider-benefit .list-item-no {
    position: absolute;
    left: 0;
    top: 0;
    display: block;
    text-align: center;
    line-height: 40px;
    width: 40px;
    height: 40px;
    background-color: #c4c4c4;
    border-radius: 50%;
    color: var(--clr_primary);
    font-size: var(--font_24_22_20_18);
    font-weight: 700;
    z-index: 1;
    transition: all linear 0.5s;
}

.provider-benefit .list-item-line {
    position: absolute;
    left: 18px;
    top: 0;
    display: block;
    width: 4px;
    height: 100%;
    background-color: #d9d9d9;
    z-index: 0;
    transition: all linear 0.5s;
}

.provider-benefit .list-item-body {
    height: 0;
    overflow: hidden;
    transition: height 0.3s ease;
}

.provider-benefit .list-item-title {
    font-size: var(--font_26_24_22_20_bs);
    font-weight: 600;
}

.provider-benefit .list-item-content {
    margin-bottom: 0;
    font-size: var(--font_20_18_16_14_bs);
    font-weight: 400;
    max-width: 550px;
}

.provider-benefit .list-item.active::before {
    background-color: var(--clr_primary_blue);
}

.provider-benefit .list-item.active::after {
    background-color: var(--clr_primary);
}

.provider-benefit .list-item.active .list-item-body {
    height: 100%;
    transform: translateY(0%);
    opacity: 1;
}

.provider-benefit .list-item:last-child {
    position: fixed;
    bottom: var(--size_20);
    left: calc(var(--size_30_half) + 60px);
    right: var(--size_10);
}
</style>

内容的提问来源于stack exchange,提问作者Vimal Chavda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 18:49:50