Impedir a rolagem automática do navegador ao atualizar

95

Se você for para uma página a e rolar ao redor, então a atualização da página será atualizada no local onde você a deixou. Isso é ótimo, mas também ocorre em páginas onde há um local de âncora no url. Um exemplo seria se você clicasse em um link http://example.com/post/244#comment5e atualizasse a página depois de olhar ao redor, você não estaria na âncora e a página saltasse. Existe alguma maneira de evitar isso com javascript? Para que não importe o que você sempre navegue até a âncora.

ThomasReggi
fonte
Uma solução jQuery está bem ou você quer js simples?
mrtsherman

Respostas:

16

Esta solução não é mais recomendada devido a mudanças no comportamento do navegador. Veja outras respostas.

Basicamente, se uma âncora for usada, nos vinculamos ao evento windows scroll. A ideia é que o primeiro evento de scroll pertença ao reposicionamento automático feito pelo navegador. Quando isso ocorre, fazemos nosso próprio reposicionamento e removemos o evento vinculado. Isso evita que as rolagens de página subsequentes prejudiquem o sistema.

$(document).ready(function() {
    if (window.location.hash) { 
        //bind to scroll function
        $(document).scroll( function() {
            var hash = window.location.hash
            var hashName = hash.substring(1, hash.length);
            var element;

            //if element has this id then scroll to it
            if ($(hash).length != 0) {
                element = $(hash);
            }
            //catch cases of links that use anchor name
            else if ($('a[name="' + hashName + '"]').length != 0)
            {
                //just use the first one in case there are multiples
                element = $('a[name="' + hashName + '"]:first');
            }

            //if we have a target then go to it
            if (element != undefined) {
                window.scrollTo(0, element.position().top);
            }
            //unbind the scroll event
            $(document).unbind("scroll");
        });
    }

});
mrtsherman
fonte
Um caso de uso no qual estou pensando que deve ser considerado é se o usuário rolar a página antes de ocorrer a rolagem automática. Pelo que me lembro, a rolagem automática só acontece depois que a página está completamente carregada. Se o usuário rolar antes, a rolagem automática é cancelada. Portanto, você precisaria de alguma forma de distinguir entre a rolagem iniciada pelo usuário e iniciada pelo navegador. Não sei como fazer isso, mas pelo que me lembro é possível.
mrtsherman de
1
Booyah! Este foi um problema divertido tarde da noite. Estou dizendo ao meu chefe que é sua culpa quando adormeço na minha mesa. Acabei de fazer uma alteração rápida para remover a instrução de retorno. Isso interferiu na desvinculação que adicionei para o evento de rolagem.
mrtsherman de
Inicialmente, coloquei isso funcionando em um pequeno arquivo de exemplo básico para verificar. Assim que confirmei que funcionava, fiquei perplexo ao ver que não estava funcionando no meu projeto. Por meio do processo de eliminação, consegui encontrar uma única declaração de estilo em meu arquivo css que estava causando a falha. Foi a aplicação de uma fonte externa. Eu envolvi seu código em uma função e agora estou passando para um manipulador $ (window) .load () dentro do manipulador doc.ready. Parece funcionar agora (com uma ligeira oscilação da página inicial). Obrigado pelo código! Deixe-me saber se isso é uma solução sólida ou não.
ThomasReggi de
1
Não funcionará se você tiver conteúdo que carrega após o carregamento da página; Ex: ter 2 div que será preenchido ajax com banners.
Decebal
@FlashThunder - você pode definir "não funciona"? Publicar uma mensagem de console?
mrtsherman
151

No Chrome, mesmo se você forçar scrollTop para 0, ele pulará depois do primeiro evento de rolagem.

Você deve vincular o pergaminho a este:

$(window).on('beforeunload', function() {
    $(window).scrollTop(0);
});

Portanto, o navegador é enganado para acreditar que estava no início antes da atualização.

josetapadas
fonte
5
Muito mais útil do que a resposta aceita se você não quiser mexer com a rolagem.
Dan Abramov
2
Isso não está funcionando no Chrome 33. Quero dizer, ele rola para o topo antes de carregar a nova página. No entanto, o navegador ainda se lembra da posição de rolagem anterior de alguma forma e executa o mesmo rolagem automática para essa posição.
Haralan Dobrev
1
Testado no Chrome 36, Firefox 30 e IE 11. Funciona muito bem!
Fizzix de
24
Para implementação não jQuery: window.onbeforeunload = function(){ window.scrollTo(0,0); }
ProfNandaa de
5
Por que você escolheu o evento 'beforeunload' em vez de 'unload'. Meus testes mostram que o último permite evitar o salto para o topo antes que a página seja realmente descarregada pelo navegador.
Aleksandr Zonov
74

Para desativar a restauração automática de rolagem, basta adicionar esta tag à seção principal.

<script>history.scrollRestoration = "manual"</script>

Não é compatível com o IE. Compatibilidade do navegador.

imos
fonte
3
Essa seria a melhor resposta se estivesse disponível no IE / Edge. Você pode votar para que seja implementado aqui: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
The Chewy
4
Esta deve ser realmente uma resposta correta em 2019. Nenhum dos outros métodos está funcionando 100%.
Limbo de
2
Posso confirmar que esta é a melhor solução. Outras soluções aqui não funcionam no Mobile Safari e podem ser complicadas. Isso funciona perfeitamente.
user3330820
20

Depois de várias falhas, finalmente consegui fazer o truque. anzo está correto aqui, pois o uso beforeunloadfará a página saltar para o topo quando um usuário recarregar a página ou clicar em um link. Assim unloadé a maneira clara de fazer isso.

$(window).on('unload', function() {
   $(window).scrollTop(0);
});

Jeito Javascript (Obrigado ProfNandaa ):

window.onunload = function(){ window.scrollTo(0,0); }

EDITAR: 16/07/2015

O problema do salto ainda está lá com o Firefox, mesmo com unload eventos.

Janaka Dombawela
fonte
3
Essa solução é muito melhor do que a beforeunloadsolução porque evita pular para o topo da página em recarregamentos e cliques de âncora.
BradGreens de
@BradGreens Com o Chrome moderno, o evento onunload também é acionado quando o usuário muda para outras guias, o que é inesperado. onbeforeunload ainda é uma solução alternativa válida.
Telvin Nguyen
@TelvinNguyen Você pode fornecer algum recurso sobre isso? Eu testei isso no google chrome 72 e ainda está funcionando bem para mim.
Janaka Dombawela
@JanakaDombawela O que afirmei: A alteração da nova guia que causaria problemas está incorreta. No entanto, você pode ver que o evento onunload neste exemplo não foi acionado corretamente, mesmo com jQuery 1.9.1 vs jQuery 1.8.3. onunload não é confiável. jsfiddle.net/6s4jhdug/3 (1.8.3) jsfiddle.net/frt45ue9 (1.9.1)
Telvin Nguyen
3

Aqui está uma abordagem mais geral. Em vez de tentar evitar que o navegador role (ou pule para o topo, como deveria), apenas restauro a posição anterior na página. Ou seja, estou gravando o deslocamento y atual da página em localStorage e role para esta posição assim que a página for carregada.

function storePagePosition() {
  var page_y = window.pageYOffset;
  localStorage.setItem("page_y", page_y);
}


window.addEventListener("scroll", storePagePosition);


var currentPageY;

try {
  currentPageY = localStorage.getItem("page_y");

  if (currentPageY === undefined) {
    localStorage.setItem("page_y") = 0;
  }

  window.scrollTo( 0, currentPageY );
} catch (e) {
    // no localStorage available
}
Oliver Schafeld
fonte
2

Você pode simplesmente colocar um # no final para que a página carregue no topo.

Funciona em todos os navegadores, mobile e desktop, porque é muito simples.

$(document).ready(function() {
var url = window.location.href;
console.log(url);
if( url.indexOf('#') < 0 ) {
    window.location.replace(url + "#");
} else {
    window.location.replace(url);
}

});

// Isso carrega a página com um # no final.

Daut
fonte
Se eu tentar fazer isso diretamente no meu servidor, funcionará como mágica. Mas, meu cms está me dando um erro de marcação. Não consigo descobrir o que é.
Alice,
1
se você estiver usando o wordpress, altere o $ para jQuery
Herzling
1

Isso funciona para mim.

    //Reset scroll top

    history.scrollRestoration = "manual"

    $(window).on('beforeunload', function(){
          $(window).scrollTop(0);
    });
Alex se divertindo
fonte
-2

Você deveria ser capaz.

Onload, verifique se window.location.hashtem um valor. Em caso afirmativo, pegue o elemento com um id que corresponda ao valor de hash. Encontre a posição do elemento (chamadas recursivas para offsetTop / offsetLeft) e, em seguida, passe esses valores para owindow.scrollTo(x, y) método.

Isso deve rolar a página até o elemento desejado.

nikmd23
fonte
3
Isso não impede que os navegadores façam uma rolagem automática. É sobre isso que se trata esta questão.
Haralan Dobrev