Положение прокрутки скачет, если DOM изменяется, когда упругая прокрутка подпрыгивает
В OS X пользователь может прокрутить окно просмотра, и браузер отскочит страницу.
Как пользователь, мне нравится этот эффект, но он вызывает неприятную ошибку на нашем сайте.
Когда пользователь нажимает большой баннер "Следующая статья" внизу страницы, загружается следующая статья и заменяется большая часть DOM на странице. Когда это происходит, я сбрасываю позицию прокрутки наверх:
window.scrollTo(0, 0);
Это обычно работает нормально. Однако, если пользователю удастся нажать "Следующая статья", когда браузер подпрыгивает на странице из-за упругой прокрутки, scrollTo
не работает должным образом. Кажется, что после замены большей части DOM и сброса положения прокрутки, некоторые оставшиеся события от эффекта отскакивания "прибывают" и заставляют прокрутку прыгать на один или два экрана ниже после того, как она была сброшена в ноль.
Как заставить браузер прокручивать до начала и игнорировать оставшиеся подпрыгивающие события?
Это происходит в WebKit.
1 ответ
Я не смог решить проблему, поэтому в качестве обходного пути я написал функцию, которая возвращает обещание. Это обещание разрешается, когда эластичная прокрутка закончена.
Когда пользователь нажимает "Следующая статья", я загружаю статью, но жду, пока обещание не будет выполнено, прежде чем я выполню операции DOM и вызову scrollTo
, Это хорошо работает для меня.
function waitForElasticScroll() {
// If user scrolls part viewport and clicks while elastic scroll
// has not fully "returned", scroll position will get messed up in Chrome.
// Our workaround is to wait for elastic scroll to finish before transitioning.
// rAF calls help avoid unnecessary layout.
return new Promise(function (resolve) {
window.requestAnimationFrame(function () {
var maxScrollY = document.body.scrollHeight - window.innerHeight;
function isReady() {
var scrollY = window.scrollY || window.pageYOffset;
return scrollY <= maxScrollY;
}
function resolveIfReady() {
if (isReady()) {
resolve();
} else {
window.requestAnimationFrame(resolveIfReady);
}
}
resolveIfReady();
});
});
}
Я использую Bluebird для Promises и анимационный фрейм для rAF polyfill.