【小程序篇】scroll-behavior:smooth导致ios和鸿蒙js驱动的动画帧数暂停

180 阅读2分钟

出现的问题

scroll-behavior: smooth 在 iOS 和鸿蒙系统中的某些情况下,确实可能导致滚动动画与 JavaScript 动画的帧数不一致,甚至暂停。这个问题主要是因为 scroll-behavior: smooth 的平滑滚动效果是由浏览器原生的滚动机制驱动的,而 JavaScript 动画(尤其是使用 requestAnimationFrame)可能会与浏览器的滚动渲染产生冲突。

解决方案

1. 禁用 scroll-behavior 在特定设备上的使用

如果你的目标是让平滑滚动在 iOS 和鸿蒙设备上不影响动画效果,可以使用 JavaScript 来检测用户的设备,并有选择性地禁用平滑滚动。

js


复制编辑
if (/iPhone|iPad|iPod|Android|HarmonyOS/i.test(navigator.userAgent)) {
  document.documentElement.style.scrollBehavior = 'auto';
} else {
  document.documentElement.style.scrollBehavior = 'smooth';
}

这个方法通过检测用户的设备来决定是否应用平滑滚动。

2. 使用 JavaScript 来实现平滑滚动

如果你想完全控制滚动效果,可以自己实现平滑滚动,而不依赖 CSS 的 scroll-behavior。这样就可以避免与 JavaScript 动画的冲突。可以使用 window.scrollTowindow.scroll 配合 requestAnimationFrame 来实现自定义平滑滚动效果。

例如,使用 requestAnimationFrame 实现自定义的平滑滚动:

js


复制编辑
function smoothScrollTo(targetY, duration = 500) {
  const startY = window.scrollY;
  const distance = targetY - startY;
  let startTime = null;

  function scrollStep(timestamp) {
    if (!startTime) startTime = timestamp;
    const progress = (timestamp - startTime) / duration;
    const scrollY = startY + distance * Math.min(progress, 1);
    window.scrollTo(0, scrollY);

    if (progress < 1) {
      requestAnimationFrame(scrollStep);
    }
  }

  requestAnimationFrame(scrollStep);
}

document.querySelector('#myLink').addEventListener('click', function (e) {
  e.preventDefault();
  const target = document.querySelector('#targetSection');
  smoothScrollTo(target.offsetTop);
});

这种方法给了你更大的控制权,同时可以避免 scroll-behavior 导致的帧数问题。

3. 优化帧数

在某些情况下,scroll-behavior 可能会导致与动画或渲染循环之间的竞争,尤其是在性能较低的设备上。可以通过减少滚动区域的元素数量、优化动画的帧数或使用 CSS 动画代替 JavaScript 动画来提高性能