Запретить браузерную прокрутку в HTML5 History popstate
=======================================================

Можно ли предотвратить поведение прокрутки документа по умолчанию при возникновении события popstate?

Наш сайт использует анимированную прокрутку jQuery и History.js, а изменения состояния должны прокручивать пользователя по разным областям страницы с помощью pushstate или popstate. Проблема в том, что браузер автоматически восстанавливает позицию прокрутки предыдущего состояния при возникновении события popstate.

Я пытался использовать элемент контейнера, установленный на 100% ширины и высоты документа, и прокручивать содержимое внутри этого контейнера. Проблема с тем, что я обнаружил, заключается в том, что он выглядит не так гладко, как прокрутка документа; особенно если вы используете много css3, таких как box-shadows и градиенты.

Я также пытался сохранить позицию прокрутки документа во время прокрутки, инициированной пользователем, и восстановить ее после того, как браузер прокручивает страницу (в открытом состоянии). Это прекрасно работает в Firefox 12, но в Chrome 19 наблюдается мерцание из-за прокрутки и восстановления страницы. Я предполагаю, что это связано с задержкой между прокруткой и событием прокрутки (когда позиция прокрутки восстанавливается).

Firefox прокручивает страницу (и запускает событие прокрутки) до того, как сработает popstate и Chrome сначала сгенерирует popstate, а затем прокручивает документ.

Все сайты, которые я видел и которые используют API истории, либо используют решение, аналогичное описанному выше, либо просто игнорируют изменение положения прокрутки, когда пользователь переходит назад / вперед (например, GitHub).

Можно ли вообще запретить прокрутку документа на событиях popstate?

[Объявлено Google](https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration) 2 сентября 2015 г.)

**Browser support:**

Chrome: поддерживается с 46)

Firefox: поддерживается с 46)

IE / Edge: не поддерживается,[**ask for support**](https://wpdev.uservoice.com/forums/257854-microsoft-edge-developer) тогда оставьте ссылку в комментарии)

Опера: поддерживается с 33)

Safari: поддерживается

Для получения дополнительной информации см.[Совместимость браузера на MDN](https://developer.mozilla.org/en-US/docs/Web/API/History#Browser_compatibility).



Вы можете установить позицию прокрутки на 0 в событии выгрузки. Вы можете прочитать об этом событии здесь:<https://developer.mozilla.org/en-US/docs/Web/Events/unload>, По сути, событие unload срабатывает прямо перед тем, как вы покинете страницу.

Установив scrollPosition в 0 при выгрузке означает, что когда вы покидаете страницу с установленным pushState, она устанавливает scrollPosition в 0. Когда вы вернетесь на эту страницу путем обновления или нажатия назад, она не будет автоматически прокручиваться.



и это должно предотвратить прокрутку браузера. Это работает только сейчас в Chrome 46 и выше, но похоже, что Firefox планирует поддерживать его тоже



окус на это при загрузке. Браузер перейдет к элементу с фокусом. Я понимаю, что это обходной путь, и основное внимание уделяется «span». не работает во всех браузерах (хм .. Safari). Надеюсь это поможет.



 нет никакого реального способа сделать это, только уродливый хакерский способ. Удаление прослушивателя события прокрутки не сработало для меня, поэтому вот мой уродливый способ сделать это:

Он работает в Chrome, FF и IE (он мигает при первом входе в IE). Любые предложения по улучшению приветствуются! Надеюсь это поможет.



 который хотел, чтобы позиция прокрутки фокусировалась на конкретном элементе при запуске posttate (кнопка назад):

Проверено и работает в Firefox.

Chrome будет прокручиваться до положения, но затем перемещается обратно в исходное место.



 вот мое решение.



`position: fixed` и указать`top` равно позиции прокрутки страницы.

Вот пример:

Да, вместо этого вы получаете мерцающую полосу прокрутки, но она меньше зла.



Firefox, я бы пошел с вашим решением сохранить положение прокрутки и восстановить его.

Я думал, что у меня есть хорошее решение Webkit, основанное на вашем описании, но я только что попробовал в Chrome 21, и кажется, что Chrome сначала прокручивает, затем запускает событие popstate, затем запускает событие scroll. Но для справки вот что я придумал:

Черная магия, такая как притворство, прокручивает страницу, перемещая`absolute` позиционируемый элемент также исключен скоростью перерисовки экрана.



[сообщалось о проблеме с ядром разработчика Mozilla уже более года](https://bugzilla.mozilla.org/show_bug.cgi?id=679458), К сожалению, билет не продвинулся. Я думаю, что Chrome тот же: нет надежного способа справиться с позицией прокрутки`onpopstate` через js, поскольку это нативное поведение браузера.

Хотя есть надежда на будущее, если вы посмотрите на[Спецификация истории HTML5](https://www.whatwg.org/specs/web-apps/current-work/multipage/history.html), который явно желает, чтобы позиция прокрутки была представлена на объекте состояния:

History objects represent their browsing context's session history as a flat list of session history entries. Each session history entry consists of a URL and optionally a state object, and may in addition have a title, a Document object, form data, a scroll position, and other information associated with it.

Это, и если вы читаете комментарии к билету Mozilla, упомянутому выше, дает некоторое представление о том, что возможно, что в ближайшем будущем положение прокрутки больше не будет восстановлено`onpopstate`по крайней мере для людей, использующих`pushState`.

К сожалению, до тех пор позиция прокрутки сохраняется, когда`pushState` используется, и`replaceState` не заменяет позицию прокрутки. В противном случае это было бы довольно легко, и вы могли бы использовать`replaceState` установить текущую позицию прокрутки каждый раз, когда пользователь прокручивал страницу (с некоторым осторожным обработчиком прокрутки).

Также, к сожалению, спецификация HTML5 не указывает, когда именно`popstate` событие должно быть запущено, оно просто говорит: & # xAB; вызывается в определенных случаях при переходе к записи истории сеанса & # xBB ;, в которой не ясно сказано, является ли это до или после; если бы это было всегда раньше, было бы возможно решение с обработкой события прокрутки, возникающего после popstate.

**Cancel the scroll event?**

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

**There's no solution for now**

Насколько я вижу, единственное, что я сейчас рекомендую, - это дождаться полной реализации спецификации HTML5 и выполнить в этом случае поведение браузера, что означает: анимировать прокрутку, когда браузер позволяет вам это делать. и позволить браузеру переместить страницу, когда есть событие истории.**The only thing you can influence position-wise is that you use `pushState` when the page is positioned in a good way to go back to.** Любое другое решение должно либо содержать ошибки, либо быть слишком специфичным для браузера, либо и тем, и другим.