窗口滚动在 Safari 中异步工作

Does window.scrollTo work asynchronously in Safari?

本文关键字:异步 工作 Safari 滚动 窗口      更新时间:2023-09-26

最近我在Safari(6.0.5(8536.30.1(,MacOS 10.8.4(中发现了非常奇怪的(在我看来(window.scrollTo行为。它似乎是异步工作的。

我的任务听起来像:

  • 使一些绝对定位的div固定定位(固定它(
  • 做一些页面滚动
  • 将先前修改的div 设置为绝对向后定位(取消固定(

因此,要取消固定此div,我必须在滚动修改完成后立即执行取消固定例程。在这里我遇到了问题。我检查的每个浏览器都正确运行,除了 Safari。

重现步骤:

  1. 在 Safari 中打开任何网页,并确保它至少可滚动 100 像素,并且初始滚动偏移量为 0
  2. 在开发工具中打开 js 控制台
  3. 执行:window.scrollTo(0, 100); console.log(document.body.scrollTop);

输出为 0。但是当我将此代码更改为 window.scrollTo(0, 100); window.setTimeout(function() {console.log(document.body.scrollTop)}, 1); 时,输出是 100,正如预期的那样。

以下是我测试过的所有其他浏览器(它工作正常(:

  • 铬 27.0.1453.110 (MacOS 10.8.4(
  • 火狐 21.0 (MacOS 10.8.4(
  • 歌剧 12.15 b1748 (MacOS 10.8.4(
  • IE 8.0.7601.17514 (Win7(

好吧,只要我的代码示例不是跨浏览器的,就可以更轻松地使用 jQuery 在任何网页上检查此行为:

var $w = $(window); 
$w.scrollTop(100); 
console.log($w.scrollTop());

var $w = $(window); 
$w.scrollTop(100); 
window.setTimeout(function() {
    console.log($w.scrollTop())
}, 1);

此行为正常还是错误?如何处理?(现在我修改了$.fn.scrollTop以返回$.Deferred而不是链接并在除 Safari 以外的所有浏览器的主线程中立即解决它(。

实际上,即使使用Safari 6.0.5(在Lion上,即OS X 10.7(,我也尝试过并未能重现您的问题。

您可以使用 https://www.browserstack.com/screenshots 运行此 jsfiddle 以确认它适用于所有 Safari 版本(5.1、6.0、6.1、7、8(。

事实上,规范说,我引用:

当用户代理要执行滚动框到位置的

平滑滚动时,它必须在用户代理定义的时间内以用户代理定义的方式更新框的滚动位置。滚动完成后,框的滚动位置必须是位置。滚动也可以通过算法或用户中止。

除非我读错了,否则 Safari 有权在对滚动进行动画处理时为您提供旧值(或实际上任何内容(。因此,如果浏览器想要将其发挥到极致,您的setTimeout方法甚至可能无法正常工作。

requestAnimationFrame中设置滚动顶部实际上解决了我在浏览器中的问题。

JavaScript

滚动函数通常同步工作。我在scrollBy()上遇到了类似的问题,我注意到它异步运行,导致我的函数崩溃。问题是浏览器具有默认的 CSS 属性scroll-behavior: smooth,这导致滚动函数自动运行,requestAnimationFrame()异步运行。确保scroll-behavior具有unset的值,或者只是在 CSS 中全局覆盖它,如下所示:

* {
  scroll-behavior: unset
}