滚动吸附一整屏方案

背景介绍

在当今的网页设计中,流畅的交互体验已成为用户评价产品品质的重要标准之一。其中,滚动吸附(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组件库

相关推荐
kyriewen7 小时前
Anthropic 估值逼近万亿美元,Claude Sonnet 5 + Claude Science 一天两连发
前端·ai编程·claude
小徐_23339 小时前
Wot UI 2.2.0 发布:Button 新增 subtle,VideoPreview 预览体验继续增强
前端·微信小程序·uni-app
天蓝色的鱼鱼11 小时前
关于 CSS 你可能不知道的属性,但关键时刻很有用
前端·css
泯泷12 小时前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
妙码生花12 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十五):优化细节、网络请求封装
前端·后端·ai编程
泯泷12 小时前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
团团崽_七分甜12 小时前
Spring Boot 核心知识点总结
前端
lichenyang45312 小时前
从一个按钮开始,理解 ASCF 框架到底在做什么
前端
古夕12 小时前
第三方 SSO 接入实践:redirect_uri 编码、回调一致性与跨项目联调
前端·vue.js