JavaScript页面滚动动画应优先用requestAnimationFrame对齐渲染帧、CSS变量+will-change驱动硬件加速,并用IntersectionObserver按需监听视口进入,避免重排重绘与同步回流。
JavaScript 实现页面滚动动画的核心是监听滚动事件并平滑更新元素状态,而优化的关键在于减少重排重绘、避免高频触发、合理使用节流或防抖,并优先采用原生 CSS 动画能力。
scroll 事件触发频率极高(每秒数十次),直接在其中执行 DOM 操作极易导致卡顿。推荐用 requestAnimationFrame 将更新逻辑“对齐”到浏览器渲染帧:
let ticking = false; let lastScrollTop = 0;function updatePosition() { const scrollTop = window.pageYOffset; // 更新动画元素:比如透明度、位移 document.querySelector('.fade-in').style.opacity = Math.min(1, scrollTop / 300); ticking = false; }
window.addEventListener('scroll', () => { if (!ticking) { requestAnimationFrame(updatePosition); ticking = true; } });
用 CSS 自定义属性 + will-change 驱动动画纯 JS 修改 style.left/top/transform 会频繁触发重排;更高效的方式是:
// JS
window.addEventListener('scroll', () => {
document.documentElement.style.setProperty('--scroll-y', `${window.scrollY}px`);
});
/ CSS /
.hero {
transform: translateY(calc(var(--scroll-y) * 0.3));
will-change: transform;
}
如果目标只是实现「元素进入视口时触发动画」,完全不需要监听整个页面滚动:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
observer.unobserve(entry.target); // 触发后停止监听
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.js-animate').forEach(el => observer.observe(el));