如何实现类似指定网站的平滑滚动(onscroll)效果?
实现高精度平滑滚动的方案
一、原生CSS基础平滑滚动
如果只需要基础的锚点跳转或全局平滑滚动,浏览器原生API就能快速实现:
html { scroll-behavior: smooth; }
局限:原生方案可控性弱,无法实现目标网站那种带物理阻尼的顺滑滚动效果,仅适合简单场景。
二、自定义JS平滑滚动(匹配目标网站的高级效果)
目标网站的滚动带有阻尼缓动、加速度控制,需要通过JS接管滚动逻辑,模拟物理运动特性:
核心实现代码
class SmoothScroll { constructor() { this.targetScroll = window.scrollY; this.currentScroll = window.scrollY; this.damping = 0.12; // 阻尼系数:0.05-0.2区间,越小越顺滑 this.scrollSensitivity = 1.3; // 滚动灵敏度系数 // 接管滚轮事件 window.addEventListener('wheel', this.handleWheel.bind(this), { passive: false }); // 逐帧更新滚动位置 requestAnimationFrame(this.updateScroll.bind(this)); } handleWheel(e) { e.preventDefault(); // 计算滚动增量,兼容不同浏览器的滚轮事件参数 const delta = e.deltaY || (e.detail ? e.detail * -40 : e.wheelDelta); this.targetScroll += delta * this.scrollSensitivity; // 限制滚动范围,防止超出文档边界 const maxScroll = document.documentElement.scrollHeight - window.innerHeight; this.targetScroll = Math.max(0, Math.min(this.targetScroll, maxScroll)); } updateScroll() { // 缓动公式:逐步逼近目标滚动位置 this.currentScroll += (this.targetScroll - this.currentScroll) * this.damping; // 消除微小差值的抖动 if (Math.abs(this.targetScroll - this.currentScroll) < 0.5) { this.currentScroll = this.targetScroll; } // 应用滚动位置 window.scrollTo(0, this.currentScroll); // 持续更新 requestAnimationFrame(this.updateScroll.bind(this)); } } // 初始化实例 new SmoothScroll();
关键参数调整
damping:控制平滑程度,0.05=超顺滑(响应稍慢),0.2=偏灵敏(平滑度降低)scrollSensitivity:适配不同设备的滚轮速度,数值越大滚动幅度越大
移动端适配(可选)
添加触摸滑动支持,补充以下代码:
// 在SmoothScroll类的constructor中添加 this.touchStartY = 0; this.touchMoveY = 0; window.addEventListener('touchstart', this.handleTouchStart.bind(this)); window.addEventListener('touchmove', this.handleTouchMove.bind(this), { passive: false }); // 新增触摸事件处理方法 handleTouchStart(e) { this.touchStartY = e.touches[0].clientY; } handleTouchMove(e) { e.preventDefault(); this.touchMoveY = e.touches[0].clientY; const delta = this.touchStartY - this.touchMoveY; this.targetScroll += delta * 2; // 调整触摸滚动灵敏度 this.touchStartY = this.touchMoveY; }
三、滚动触发元素动画(可选)
如果需要像目标网站那样,滚动时伴随元素淡入、位移效果,结合Intersection Observer实现:
const animateObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('active'); } }); }, { threshold: 0.1 }); // 给需要动画的元素添加观察 document.querySelectorAll('.scroll-animate').forEach(el => { animateObserver.observe(el); });
对应的CSS:
.scroll-animate { opacity: 0; transform: translateY(25px); transition: all 0.7s cubic-bezier(0.2, 0.8, 0.2, 1); } .scroll-animate.active { opacity: 1; transform: translateY(0); }
内容的提问来源于stack exchange,提问作者MishaGavura
相关产品推荐
相关产品推荐

