Does window.scrollTo work asynchronously in Safari?

只愿长相守 提交于 2020-08-24 06:05:28

问题


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).


回答1:


I actually just tried and failed to reproduce your problem even with Safari 6.0.5 (on Lion, i.e. OS X 10.7).

You can run this jsfiddle with https://www.browserstack.com/screenshots to confirm that it works with all Safari versions (5.1, 6.0, 6.1, 7, 8).

Indeed the spec says and I quote:

When a user agent is to perform a smooth scroll of a scrolling box box to position, it must update the scroll position of box in a user-agent-defined fashion over a user-agent-defined amount of time. When the scroll is completed, the scroll position of box must be position. The scroll can also be aborted, either by an algorithm or by the user.

Unless I am reading it wrong, Safari has its right to give you the old value (or indeed anything) while it is animating the scroll. Therefore your setTimeout approach may not even work fine if the browsers want to take it to the extreme.




回答2:


Setting scroll top in requestAnimationFrame actually solved my issue in browsers.




回答3:


JavaScript scroll functions generally work synchronously. I had a similar problem with scrollBy() where I've noticed that it was running asynchronously which caused my function to crash. The problem was that the browser had the default CSS-property scroll-behavior: smooth which caused the scroll function to automatically run with requestAnimationFrame() which runs asynchronously. Make sure that the scroll-behavior has the value unset or just overwrite it globally in your CSS like this:

* {
  scroll-behavior: unset
}


来源:https://stackoverflow.com/questions/17212799/does-window-scrollto-work-asynchronously-in-safari

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!