Запретить браузерную прокрутку в 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?

 Sean Hogan26 мая 2012 г., 13:13
Возможно, вам удастся прочесть измерение элемента (для принудительного переформатирования страницы) после установки положения прокрутки. напримерdocument.body.clientHeight но я не видел, чтобы это работало во всех браузерах.
 Jeff Wooden15 авг. 2012 г., 22:56
Что, если бы вы манипулировали функцией прокрутки документа, вот где я бы начал, по крайней мере. Для этого есть решение:stackoverflow.com/questions/7035331/…

Ответы на вопрос(11)

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

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

//Listen for unload event. This is triggered when leaving the page.
//Reference: https://developer.mozilla.org/en-US/docs/Web/Events/unload
window.addEventListener('unload', function(e) {
    //set scroll position to the top of the page.
    window.scrollTo(0, 0);
});

history.scrollRestoration = 'manual';

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

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

Решение Вопроса
if 'scrollRestoration' in history) {
  history.scrollRestoration = 'manual';
}

Объявлено Google 2 сентября 2015 г.)

Browser support:

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

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

IE / Edge: не поддерживается,ask for support тогда оставьте ссылку в комментарии)

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

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

Для получения дополнительной информации см.Совместимость браузера на MDN.

 09 февр. 2019 г., 18:23
Короче:history.scrollRestoration && history.scrollRestoration = 'manual'; или дажеvar sr = 'scrollRestoration'; history[sr] && history[sr] = 'manual';

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

/// GLOBAL VARS ////////////////////////
var saveScrollPos = false;
var scrollPosSaved = window.pageYOffset;
////////////////////////////////////////

jQuery(document).ready(function($){

    //// Go back with keyboard shortcuts ////
    $(window).keydown(function(e){
        var key = e.keyCode || e.charCode;

        if((e.altKey && key == 37) || (e.altKey && key == 39) || key == 8)
        saveScrollPos = false;
    });
    /////////////////////////////////////////

    //// Go back with back button ////
    $("html").bind("mouseout",  function(){ saveScrollPos = false; });
    //////////////////////////////////

    $("html").bind("mousemove", function(){ saveScrollPos = true; });

    $(window).scroll(function(){
        if(saveScrollPos)
        scrollPosSaved = window.pageYOffset;
        else
        window.scrollTo(0, scrollPosSaved);
    });

});

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

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

$(document).ready(function () {

     if (window.history.pushState) {
        //if push supported - push current page onto stack:
        window.history.pushState(null, document.title, document.location.href);
    }

    //add handler:
    $(window).on('popstate', PopStateHandler);
}

//fires when the back button is pressed:
function PopStateHandler(e) {
    emnt= $('#elementID');
    window.scrollTo(0, emnt.position().top);
    alert('scrolling to position');
}

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

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

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

window.addEventListener('popstate', function(e) {
    var scrollTop = document.body.scrollTop;
    window.addEventListener('scroll', function(e) {
        document.body.scrollTop = scrollTop;
    });
});

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

Вот пример:

$(window).on('popstate', function()
{
   $('.yourWrapAroundAllContent').css({
      position: 'fixed',
      top: -window.scrollY
   });

   requestAnimationFrame(function()
   {
      $('.yourWrapAroundAllContent').css({
         position: 'static',
         top: 0
      });          
   });
});

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

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

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

function noScrollOnce(event) {
    event.preventDefault();
    document.removeEventListener('scroll', noScrollOnce);
}
window.onpopstate = function () {
    document.addEventListener('scroll', noScrollOnce);
};​

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

Таким образом, я на 99% уверен, что ответ таков, что вы не можете, и вам придется использовать один из компромиссов, упомянутых вами в вопросе. Оба браузера выполняют прокрутку до того, как JavaScript узнает об этом, поэтому JavaScript может реагировать только после события. Единственное отличие состоит в том, что Firefox не рисует экран до тех пор, пока не будет запущен Javascript, поэтому в Firefox есть работоспособное решение, но не в WebKit.

сообщалось о проблеме с ядром разработчика Mozilla уже более года, К сожалению, билет не продвинулся. Я думаю, что Chrome тот же: нет надежного способа справиться с позицией прокруткиonpopstate через js, поскольку это нативное поведение браузера.

Хотя есть надежда на будущее, если вы посмотрите наСпецификация истории HTML5, который явно желает, чтобы позиция прокрутки была представлена на объекте состояния:

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. Любое другое решение должно либо содержать ошибки, либо быть слишком специфичным для браузера, либо и тем, и другим.

 09 окт. 2014 г., 21:39
Формулировка спецификации истории теперь немного другая. Кроме того, если вы прокрутите вниз и посмотрите на документацию по pushState, там не будет упоминания о добавлении позиции прокрутки. Спецификация предполагает, что запись истории сеанса может содержать сохраненную позицию прокрутки, но я не уверен, что это означает, что веб-разработчик сможет установить ее.

window.onpopstate = function(event) {
  return false;
};
 20 авг. 2012 г., 13:16
Это не работает. Некоторые события не могут быть предотвращены, и popstate является одним из них.

Ваш ответ на вопрос