11

Recently I found very strange(in my opinion) window.scrollTo behaviour in Safari(6.0.5 (8536.30.1), MacOS 10.8.4). It seems it works asynchronously.

My task sounds like:

  • make some absolute positioned div to be fixed positioned (pin it)
  • do some page scroll
  • make previously modified div to be absolutely positioned back (unpin it)

So to unpin this div I have to execute unpin routine just after scroll modification is complete. And here I met the problem. Every browser I checked does it correctly except Safari.

Steps to reproduce:

  1. Open any web page in Safari and make sure it is scrollable at least for 100px and it's initial scroll offset is 0
  2. Open js console in dev tools
  3. execute: window.scrollTo(0, 100); console.log(document.body.scrollTop);

The output is 0. But when I change this code to window.scrollTo(0, 100); window.setTimeout(function() {console.log(document.body.scrollTop)}, 1); the output is 100, as expected.

Here are all other browsers I've tested(where it works fine):

  • Chrome 27.0.1453.110 (MacOS 10.8.4)
  • Firefox 21.0 (MacOS 10.8.4)
  • Opera 12.15 b1748 (MacOS 10.8.4)
  • IE 8.0.7601.17514 (Win7)

Well, as soon as my code sample is not cross browser, it's easier to check this behaviour on any web page with jQuery:

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

VS

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

Is this behavior is ok or is it a bug? How to handle it? (Now I modified $.fn.scrollTop to return $.Deferred instead of chaining and resolve it instantly in main thread in all browsers except Safari).

4

3 回答 3

1

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

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

确实,规范说,我引用:

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

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

于 2015-07-10T09:11:42.940 回答
1

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

于 2017-03-20T11:44:56.617 回答
0

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

* {
  scroll-behavior: unset
}
于 2020-01-02T07:13:38.030 回答