滚动吸附一整屏方案

背景介绍

在当今的网页设计中,流畅的交互体验已成为用户评价产品品质的重要标准之一。其中,滚动吸附(Scroll Snapping) 作为一种常见的交互模式,通过将滚动内容自动对齐到预设的"吸附点"(如视口的顶部、底部或页面边界),为用户提供了一种精准、顺滑的浏览体验。这种技术被广泛应用于全屏轮播图、垂直/横向分页导航、长表单分步填写等场景,尤其在移动端触屏设备中,手指滑动后内容自动"吸附"到完整屏幕的特性,显著降低了用户的操作成本。

方法一:纯 CSS 实现

  • 使用 scroll-snap-type: y mandatory 启用垂直滚动吸附
  • 每个 section 设置 scroll-snap-align: start 对齐顶部
  • 隐藏滚动条提升美观度(可选)
xml 复制代码
<!DOCTYPE html>
<meta charset="UTF-8">
<head>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    .container {
      height: 100vh;
      overflow-y: scroll;
      scroll-snap-type: y mandatory;
      scroll-behavior: smooth;
    }

    section {
      height: 100vh;
      scroll-snap-align: start;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 4em;
    }

    /* 可选:隐藏滚动条 */
    .container::-webkit-scrollbar {
      display: none;
    }
  </style>
</head>
<body>
<div class="container">
  <section style="background: #ff6b6b;">第一屏</section>
  <section style="background: #4ecdc4;">第二屏</section>
  <section style="background: #45b7d1;">第三屏</section>
  <section style="background: #96ceb4;">第四屏</section>
</div>
</body>
</html>

方法二:JavaScript 增强控制

  • 监听鼠标滚轮事件
  • 判断滚动方向(上/下)
  • 使用 scrollIntoView() 实现平滑滚动
  • 通过 flag 防止滚动冲突
xml 复制代码
<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    .container {
      height: 100vh;
      overflow-y: scroll;
      scroll-behavior: smooth;
      -webkit-overflow-scrolling: touch; /* 移动端滚动优化 */
    }

    section {
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 4em;
      scroll-snap-align: start; /* 辅助平滑定位 */
    }
  </style>
</head>
<body>
<div class="container">
  <section style="background: #ff6b6b;">第一屏</section>
  <section style="background: #4ecdc4;">第二屏</section>
  <section style="background: #45b7d1;">第三屏</section>
  <section style="background: #96ceb4;">第四屏</section>
</div>

<script>
  let current = 0;
  let startY = 0;
  const sections = document.querySelectorAll('section');
  const container = document.querySelector('.container');
  let isScrolling = false;
  const threshold = 50; // 滑动阈值

  // 桌面端滚轮事件
  container.addEventListener('wheel', handleWheel, { passive: false });

  // 移动端触摸事件
  container.addEventListener('touchstart', handleTouchStart, { passive: false });
  container.addEventListener('touchend', handleTouchEnd, { passive: false });

  // 滚动事件
  function handleWheel(e) {
    e.preventDefault();
    if (isScrolling) return;

    const delta = Math.sign(e.deltaY);
    navigate(delta);
  }

  // 点击开始,如果是PC可以不要
  function handleTouchStart(e) {
    startY = e.touches[0].clientY;
  }

  // 点击结束,如果是PC可以不要
  function handleTouchEnd(e) {
    if (isScrolling) return;

    const endY = e.changedTouches[0].clientY;
    const delta = startY - endY; // 滑动距离

    if (Math.abs(delta) > threshold) {
      navigate(delta > 0 ? 1 : -1);
    }
  }

  // 计算滚动的最终位置
  function navigate(direction) {
    const newIndex = current + direction;

    if (newIndex >= 0 && newIndex < sections.length) {
      current = newIndex;
      scrollToSection();
    }
  }

  // 滑动
  function scrollToSection() {
    isScrolling = true;
    sections[current].scrollIntoView({
      behavior: 'smooth',
      block: 'start'
    });

    setTimeout(() => {
      isScrolling = false;
    }, 800);
  }

  // 禁用移动端双指缩放,如果是PC可以不要
  document.addEventListener('gesturestart', (e) => e.preventDefault());
  document.addEventListener('gesturechange', (e) => e.preventDefault());
</script>
</body>
</html>

总结

  • 推荐优先使用 CSS 方案,性能更好且代码更简洁
  • 可以通过修改 scroll-behavior 或动画时间调整滚动速度
  • 确保内容区块高度严格等于视口高度(100vh)

往期文章

唤起小程序呕血总结

h5跳转小程序指北

简单易上手!发布React + Vite + Storybook组件库

相关推荐
Watermelo6173 分钟前
前端如何应对精确数字运算?用BigNumber.js解决JavaScript原生Number类型在处理大数或高精度计算时的局限性
开发语言·前端·javascript·vue.js·前端框架·vue·es6
HebyH_4 分钟前
2025前端面试遇到的问题(vue+uniapp+js+css)
前端·javascript·vue.js·面试·uni-app
Clockwiseee8 分钟前
CSRF记录
前端·csrf
深圳卢先生10 分钟前
XSS 和 CSRF 有什么区别?Java Web 如何防御?
前端·xss·csrf
qq_386322693 小时前
华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)
前端·网络·学习
蓝婷儿8 小时前
前端面试每日三题 - Day 32
前端·面试·职场和发展
星空寻流年9 小时前
CSS3(BFC)
前端·microsoft·css3
九月TTS9 小时前
开源分享:TTS-Web-Vue系列:Vue3实现固定顶部与吸顶模式组件
前端·vue.js·开源
CodeCraft Studio10 小时前
数据透视表控件DHTMLX Pivot v2.1发布,新增HTML 模板、增强样式等多个功能
前端·javascript·ui·甘特图
一把年纪学编程10 小时前
【牛马技巧】word统计每一段的字数接近“字数统计”
前端·数据库·word