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

如何实现随滚动动画的竖直线及分页式页面切换效果

分页式竖直线切换动画解决方案

我希望实现一条随页面元素位置变化的竖直线动画,效果是分页切换——滚动时竖直线移动,切换显示不同section的内容。当前代码存在以下问题:

  • 竖直线滚动时会移到屏幕极端位置,停止后回到默认位置
  • 竖直线无法覆盖section1的元素
  • section2的内容无法在竖直线移动后正确显示

完整解决方案代码

HTML

<section id="s1" class="page-section active">
    <div class="page-container">
        <div class="row">
            <div class="col content-col">
                <div>
                    <p class="about-text-title">Label1</p>
                    <p class="about-text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Provident nulla iure quod autem amet, ipsa beatae voluptatibus maiores adipisci quae, expedita deserunt laborum architecto corporis dolore. Voluptates tenetur nisi cupiditate?</p>
                </div>
            </div>
            <div class="col content-col">
                <p>Video frame</p>
            </div>
        </div>
    </div>
</section>
<section id="s2" class="page-section">
    <div class="page-container">
        <div class="row">
            <div class="col content-col">
                <p>Label2</p>
                <p class="about-text">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Provident nulla iure quod autem amet, ipsa beatae voluptatibus maiores adipisci quae, expedita deserunt laborum architecto corporis dolore. Voluptates tenetur nisi cupiditate?</p>
            </div>
            <div class="col content-col">
                <p>Another video frame</p>
            </div>
        </div>
    </div>
</section>

<!-- 竖直线单独放在页面顶层 -->
<div class="vertical-line"></div>

CSS

/* 基础全局样式重置 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    overflow: hidden; /* 隐藏滚动条,用自定义分页逻辑 */
    height: 100vh;
}

.page-section {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.5s ease;
}

.page-section.active {
    visibility: visible;
    opacity: 1;
}

.page-container {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
}

.row {
    display: flex;
    width: 100%;
    justify-content: space-between;
}

.content-col {
    padding: 0 8.125rem;
    flex: 1;
    position: relative;
    z-index: 1; /* 让内容在竖直线下方 */
}

.vertical-line {
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    height: 100vh;
    background-color: #000; /* 替换成你的--primary-text颜色 */
    z-index: 10; /* 确保竖直线在内容上方 */
    transition: transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 竖直线移动到左侧的状态 */
.vertical-line.left {
    transform: translateX(-100vw);
}

/* 竖直线移动到右侧的状态 */
.vertical-line.right {
    transform: translateX(100vw);
}

JavaScript

document.addEventListener('DOMContentLoaded', function() {
    const line = document.querySelector('.vertical-line');
    const sections = document.querySelectorAll('.page-section');
    let currentSectionIndex = 0;
    let isAnimating = false; // 防止滚动触发多次动画冲突

    // 初始化显示第一个section
    sections[currentSectionIndex].classList.add('active');

    // 监听鼠标滚轮/触摸滚动事件
    window.addEventListener('wheel', handleScroll);
    window.addEventListener('touchmove', handleScroll, { passive: false });

    function handleScroll(e) {
        if (isAnimating) return;
        
        // 判断滚动方向:向上滚动是负数,向下是正数
        const delta = e.deltaY || (e.touches?.[0]?.clientY - lastTouchY);
        if (delta > 0) {
            // 向下滚动,切换到下一个section
            if (currentSectionIndex >= sections.length - 1) return;
            switchSection('down');
        } else {
            // 向上滚动,切换到上一个section
            if (currentSectionIndex <= 0) return;
            switchSection('up');
        }

        if (e.type === 'touchmove') {
            e.preventDefault();
            lastTouchY = e.touches[0].clientY;
        }
    }

    let lastTouchY = 0;

    function switchSection(direction) {
        isAnimating = true;
        
        // 根据方向设置竖直线的移动类
        line.classList.add(direction === 'down' ? 'right' : 'left');

        // 等待竖直线动画完成后切换section
        setTimeout(() => {
            // 隐藏当前section
            sections[currentSectionIndex].classList.remove('active');
            
            // 更新当前section索引
            currentSectionIndex = direction === 'down' ? currentSectionIndex + 1 : currentSectionIndex - 1;
            
            // 显示新的section
            sections[currentSectionIndex].classList.add('active');
            
            // 重置竖直线位置
            line.classList.remove('right', 'left');
            
            // 动画结束后允许再次触发
            setTimeout(() => {
                isAnimating = false;
            }, 100);
        }, 800); // 对应CSS中竖直线的transition时长
    }
});

关键修改说明

  • HTML结构调整:

    • 把竖直线从section内部移到全局,确保它能覆盖所有页面内容
    • 给每个section添加统一的page-section类,用active类控制显示状态
    • 内容列添加content-col类,明确层级关系
  • CSS核心改动:

    • 设置body为overflow: hidden,禁用原生滚动,实现分页式切换
    • 每个section占满全屏,通过visibility和opacity控制显示/隐藏
    • 竖直线设为fixed定位,层级设为最高,确保能覆盖内容
    • 定义left/right类控制竖直线的左右移动动画
  • JavaScript逻辑优化:

    • 使用isAnimating锁防止滚动触发多次动画冲突
    • 监听滚轮和触摸滚动事件,判断滚动方向
    • 先执行竖直线移动动画,动画完成后再切换section的显示状态,实现连贯的分页效果
    • 重置竖直线位置,为下一次切换做准备

内容的提问来源于stack exchange,提问作者Sergey Bakaev Rettley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:07:06