Работает ли window.scrollTo асинхронно в Safari?

Недавно я нашел очень странное (на мой взгляд) окно window.scrollTo в Safari (6.0.5 (8536.30.1), MacOS 10.8.4). Кажется, он работает асинхронно.

Моя задача звучит так:

  • установите фиксированное положение абсолютного положения div (выведите его)
  • выполнить прокрутку страницы
  • сделать ранее измененный div, чтобы он был полностью расположен назад (отменить)

Итак, чтобы разблокировать этот div, я должен выполнить процедуру unpin сразу после завершения модификации прокрутки. И здесь я столкнулся с проблемой. Каждый проверенный мной браузер делает это правильно, кроме Safari.

Шаги для воспроизведения:

  • Откройте любую веб-страницу в Safari и убедитесь, что она прокручивается, по крайней мере, для 100px, и начальное смещение прокрутки - 0
  • Откройте консоль js в инструментах разработчика
  • выполнить: window.scrollTo(0, 100); console.log(document.body.scrollTop);

Выход равен 0. Но когда я меняю этот код на window.scrollTo(0, 100); window.setTimeout(function() {console.log(document.body.scrollTop)}, 1);, результат равен 100.

Вот все другие браузеры, которые я тестировал (где он работает нормально):

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

Хорошо, как только мой пример кода не является перекрестным браузером, проще проверить это поведение на любой веб-странице с помощью 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);

Это нормально, или это ошибка? Как с этим справиться? (Теперь я изменил $.fn.scrollTop, чтобы вернуть $.Deferred вместо цепочки и мгновенно разрешить его в основном потоке во всех браузерах, кроме Safari).

Ответ 1

Я просто попробовал и не смог воспроизвести вашу проблему даже с Safari 6.0.5 (на Lion, то есть OS X 10.7).

Вы можете запустить jsfiddle с помощью https://www.browserstack.com/screenshots подтвердить, что он работает со всеми версиями Safari (5.1, 6.0, 6.1, 7, 8).

Действительно, spec говорит, и я цитирую:

Когда пользовательский агент должен выполнить гладкую прокрутку окна скроллинга в позицию, он должен обновить позицию прокрутки окна в определенном пользователем порядке в течение определенного пользователем периода времени. Когда свиток завершен, положение прокрутки окна должно быть позицией. Прокрутка также может быть прервана либо алгоритмом, либо пользователем.

Если я не читаю это неправильно, Safari имеет право дать вам старую ценность (или даже что-нибудь), пока она оживляет свиток. Поэтому ваш подход setTimeout может даже не работать нормально, если браузеры хотят довести его до крайности.

Ответ 2

Настройка прокрутки вверх в requestAnimationFrame действительно решила мою проблему в браузерах.