全屏滚动效果实现方案
Published on Jun 06, 2025, with 26 view(s) and 0 comment(s)
Ai 摘要:本文对比了三种实现全屏滚动吸附效果的技术方案:1)纯CSS的Scroll Snap方案,通过`scroll-snap`属性实现零依赖吸附,但快速滚动时体验不佳;2)使用现成库(如fullPage.js、Swiper等),适合快速开发但需引入外部依赖;3)JavaScript结合CSS动画的方案,通过监听滚动事件并控制`transform`实现弹性动画,兼容性好但需手动处理逻辑。每种方案均附有代码示例,开发者可根据项目需求选择。

方案 1:纯 CSS Scroll Snap

原理:利用 CSS 的 scroll-snap 属性实现无 JS 吸附滚动
优点:零依赖、性能最佳、代码简洁

问题:鼠标连续滚动时体验不佳,scroll-snap的机制是在滚动操作结束后才会触发吸附,快速连续滚动时,由于滚动并未真正"结束",可能导致吸附行为不能及时生效

<!DOCTYPE html>
<style>
  html, body { margin: 0; height: 100%; }
  .scroll-container {
    height: 100vh;
    overflow-y: scroll;
    scroll-snap-type: y mandatory; /* 关键属性 */
  }
  .page {
    height: 100vh;
    scroll-snap-align: start; /* 吸附点 */
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 3rem;
  }
  .page:nth-child(1) { background: #FF6B6B; }
  .page:nth-child(2) { background: #4ECDC4; }
  .page:nth-child(3) { background: #45B7D1; }
</style>

<div class="scroll-container">
  <section class="page">Page 1</section>
  <section class="page">Page 2</section>
  <section class="page">Page 3</section>
</div>

方案 2:使用现成库(快速开发)

推荐库

示例(fullPage.js)

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.15/fullpage.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.15/fullpage.min.js"></script>

<div id="fullpage">
  <div class="section">第一屏</div>
  <div class="section">第二屏</div>
  <div class="section">第三屏</div>
</div>

<script>
  new fullpage('#fullpage', {
    licenseKey: 'OPEN-SOURCE-GPLV3-LICENSE'
  });
</script>

方案 3:JavaScript + CSS 动画

原理:监听滚动事件,用 transform 动画移动页面
优点:兼容性更好,可控制动画曲线
缺点:需要手动处理滚动逻辑

<!DOCTYPE html>
<html>
<head>
<style>
        body { margin: 0; overflow: hidden; }
        .page { 
            width: 100%; 
            height: 100vh; 
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 3rem;
            color: white;
        }
        #container { 
            transition: transform 0.8s cubic-bezier(0.22, 1, 0.36, 1); /* 弹性动画 */
        }
        .page:nth-child(1) { background: #FF6B6B; }
        .page:nth-child(2) { background: #4ECDC4; }
        .page:nth-child(3) { background: #45B7D1; }
    </style>
</head>
<body>
    <div id="container">
        <div class="page">第一屏</div>
        <div class="page">第二屏</div>
        <div class="page">第三屏</div>
    </div>

<script>
        let current = 0;
        let isAnimating = false; // 动画锁定标志
        const container = document.getElementById("container");
        const pageCount = document.querySelectorAll('.page').length;
        
        function goToPage(newPage) {
            if (isAnimating) return;
            if (newPage < 0 || newPage >= pageCount) return;
            
            isAnimating = true;
            current = newPage;
            container.style.transform = `translateY(-${current * 100}vh)`;
            
            // 动画结束后解锁
            setTimeout(() => isAnimating = false, 800);
        }
        
        window.addEventListener('wheel', (e) => {
            e.preventDefault(); // 阻止默认滚动
            if (e.deltaY > 0) goToPage(current + 1); // 向下滚动
            if (e.deltaY < 0) goToPage(current - 1); // 向上滚动
        }, { passive: false });
    </script>
</body>
</html>