如何使用原生JavaScript实现scroll-behavior: smooth平滑滚动效果
纯JavaScript实现等效于
scroll-behavior: smooth的平滑滚动方法 你已经写的CSS scroll-behavior: smooth是浏览器原生实现的全局平滑滚动,用JS实现同等效果分两种场景,按需选择即可:
方案1:调用原生滚动API(最推荐,和CSS效果完全一致)
scrollIntoView和scrollTo本身就支持平滑滚动参数,效果和CSS全局设置的平滑滚动完全同源,不需要自己写动画逻辑,代码量最少、性能最好。
- 滚动到指定DOM元素:
// 先获取目标元素 const target = document.querySelector('#your-target-id') // 触发平滑滚动 target.scrollIntoView({ behavior: 'smooth', block: 'start', // 滚动后元素顶部和视口顶部对齐,和锚点跳转默认行为一致 inline: 'nearest' })
- 滚动到页面指定坐标位置:
// 比如滚动到距离页面顶部800px的位置 window.scrollTo({ top: 800, left: 0, behavior: 'smooth' })
小提示:如果页面已经全局设置了
scroll-behavior: smooth,哪怕调用这两个方法的时候不传behavior参数,默认也会走平滑滚动;如果某次滚动需要跳过硬动画,显式传behavior: 'instant'即可覆盖全局配置。
方案2:手动实现自定义缓动滚动(适合需要自定义动画节奏的场景)
如果你需要自己控制滚动时长、缓动曲线,不想依赖原生的默认平滑逻辑,可以基于requestAnimationFrame手写动画,效果可以做到和原生几乎无差,灵活性更高。
直接复用下面的工具函数就行:
/** * 自定义平滑滚动 * @param {HTMLElement|number} target 滚动目标:传DOM元素就滚动到对应元素位置,传数字就滚动到对应页面高度 * @param {number} duration 动画时长,单位ms,原生smooth默认时长在300-500ms区间随滚动距离动态变化 */ function smoothScroll(target, duration = 400) { const startY = window.pageYOffset // 计算目标位置的Y坐标 const targetY = typeof target === 'number' ? target : target.getBoundingClientRect().top + window.pageYOffset const totalDistance = targetY - startY let animationStart = null // 缓动函数:easeInOutQuad,感知上和浏览器原生平滑滚动的缓动节奏最接近 const ease = t => t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t function runAnimation(timestamp) { if (!animationStart) animationStart = timestamp const timePassed = timestamp - animationStart const progress = Math.min(timePassed / duration, 1) const currentY = startY + totalDistance * ease(progress) window.scrollTo(0, currentY) // 动画未完成就继续执行下一帧 if (progress < 1) requestAnimationFrame(runAnimation) } requestAnimationFrame(runAnimation) } // 调用示例1:滚动到class为card的元素位置 smoothScroll(document.querySelector('.card')) // 调用示例2:滚动回页面顶部 smoothScroll(0)
几个实现细节说明:
- 用
requestAnimationFrame执行动画是为了和浏览器屏幕刷新频率同步,不会出现掉帧、卡顿的问题,比用setTimeout写的动画流畅很多 - 如果要实现局部容器的平滑滚动,只需要把代码里的
window.pageYOffset替换成容器元素的scrollTop,window.scrollTo替换成容器元素的scrollTo方法即可 - 生产环境使用建议加个中断逻辑:监听用户的鼠标滚轮、滚动条拖动事件,一旦检测到用户主动操作滚动,就取消未完成的动画任务,避免和用户操作冲突
兼容性说明
原生API的behavior: 'smooth'配置支持所有现代浏览器(Chrome 61+、Firefox 36+、Safari 15.4+),如果不需要兼容IE等老旧浏览器,优先选方案1就够;如果需要兼容更低版本浏览器,再用方案2的自定义实现。
内容的提问来源于stack exchange,提问作者srohome
相关产品推荐
相关产品推荐

