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

如何实现整站文档的惯性平滑滚动(纯JS/HTML/CSS实现)

原生实现全站惯性平滑滚动方案

你要的滚轮滚动全程顺滑、停止带缓动延迟的效果,通过拦截原生滚动+requestAnimationFrame自定义缓动动画即可实现,html { scroll-behavior: smooth; } 只能处理锚点跳转的平滑,做不到惯性缓停,下面是完整可直接用的无依赖实现:

核心实现逻辑

  • 禁用浏览器原生滚轮滚动行为,避免和自定义动画冲突
  • 用线性插值算法逐帧计算滚动位置,实现启动柔和、减速缓停的惯性手感
  • 自动适配页面内容高度,处理滚动边界,不会出现超出页面范围的问题
  • 兼容鼠标滚轮、触摸板双指滚动场景

完整CSS代码

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  scroll-behavior: auto !important;
  overflow: hidden;
}
.scroll-container {
  width: 100%;
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
  /* 隐藏原生滚动条,需要自定义滚动条可删除下面两行 */
  scrollbar-width: none;
}
.scroll-container::-webkit-scrollbar {
  display: none;
}

完整JS代码

class SmoothScroll {
  constructor(options = {}) {
    // 可自定义手感参数
    this.config = {
      speed: options.speed ?? 0.85, // 滚动速度系数,越大滚动越快
      ease: options.ease ?? 0.08, // 缓动系数,越小启动/停止越柔和
      threshold: options.threshold ?? 0.15 // 动画停止判定阈值
    }
    this.currentScroll = 0
    this.targetScroll = 0
    this.container = null
    this.rafId = null
    this.init()
  }

  init() {
    // 创建滚动容器,自动包裹页面原有内容
    this.container = document.createElement('div')
    this.container.className = 'scroll-container'
    while(document.body.firstChild) {
      this.container.appendChild(document.body.firstChild)
    }
    document.body.appendChild(this.container)
    this.bindEvents()
    this.animationLoop()
  }

  bindEvents() {
    // 拦截滚轮事件
    window.addEventListener('wheel', (e) => {
      e.preventDefault()
      this.targetScroll += e.deltaY * this.config.speed
      // 限制滚动边界
      const maxScroll = this.container.scrollHeight - window.innerHeight
      this.targetScroll = Math.max(0, Math.min(this.targetScroll, maxScroll))
    }, { passive: false })

    // 窗口resize时重新校准边界
    window.addEventListener('resize', () => {
      const maxScroll = this.container.scrollHeight - window.innerHeight
      this.targetScroll = Math.max(0, Math.min(this.targetScroll, maxScroll))
      this.currentScroll = Math.max(0, Math.min(this.currentScroll, maxScroll))
    })
  }

  animationLoop() {
    // 线性插值计算当前滚动位置,实现缓动效果
    this.currentScroll += (this.targetScroll - this.currentScroll) * this.config.ease
    // 接近目标位置时直接归位,避免微小抖动
    if(Math.abs(this.targetScroll - this.currentScroll) < this.config.threshold) {
      this.currentScroll = this.targetScroll
    }
    this.container.scrollTop = this.currentScroll
    this.rafId = requestAnimationFrame(() => this.animationLoop())
  }

  // 对外暴露手动滚动方法,兼容锚点跳转、回到顶部这类需求
  scrollTo(targetY, isInstant = false) {
    this.targetScroll = targetY
    if(isInstant) this.currentScroll = targetY
  }

  destroy() {
    cancelAnimationFrame(this.rafId)
  }
}

// DOM加载完成后自动初始化
document.addEventListener('DOMContentLoaded', () => {
  window.smoothScroll = new SmoothScroll({
    speed: 0.9,
    ease: 0.075
  })
})

使用说明

  • 把上述CSS和JS加入页面即可直接生效,不需要改动原有页面结构,脚本会自动把所有页面内容移入滚动容器
  • 可以通过调整SmoothScroll初始化时的参数匹配你想要的手感:ease值调小会让滚动更柔和、停止延迟更长,调大则手感更跟手
  • 如果需要显示自定义滚动条,删掉CSS里隐藏滚动条的代码,自行给.scroll-container写滚动条样式即可
  • 页面动态加载内容(比如懒加载、无限滚动)时不需要额外调用API,脚本会自动识别新的内容高度,滚动边界会自动适配
  • 所有现代浏览器都兼容,不需要polyfill

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 06:19:28