Работает ли 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
действительно решила мою проблему в браузерах.