Empêcher le défilement automatique du navigateur lors de l'actualisation

95

Si vous allez sur une page et faites défiler la page, actualisez la page à l'endroit où vous l'avez laissée. C'est génial, mais cela se produit également sur les pages où il y a un emplacement d'ancrage dans l'URL. Un exemple serait si vous avez cliqué sur un lien http://example.com/post/244#comment5et actualisé la page après avoir regardé autour de vous, vous ne seriez pas à l'ancre et la page saute. Existe-t-il un moyen d'empêcher cela avec JavaScript? Ainsi, quoi qu'il en soit, vous naviguiez toujours vers l'ancre.

ThomasReggi
la source
Une solution jQuery est-elle correcte ou voulez-vous des js simples?
mrtsherman

Réponses:

16

Cette solution n'est plus recommandée en raison des changements de comportement du navigateur. Voir d'autres réponses.

Fondamentalement, si une ancre est utilisée, nous nous lions à l'événement de défilement de Windows. L'idée étant que le premier événement de défilement doit appartenir au repositionnement automatique effectué par le navigateur. Lorsque cela se produit, nous effectuons notre propre repositionnement, puis supprimons l'événement lié. Cela empêche les défilements de page suivants de perturber le système.

$(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
la source
Un cas d'utilisation auquel je pense qui devrait être pris en compte est si l'utilisateur fait défiler la page avant le défilement automatique. Si je me souviens bien, le défilement automatique ne se produit qu'après le chargement complet de la page. Si l'utilisateur fait défiler avant, le défilement automatique est annulé. Vous auriez donc besoin d'un moyen de faire la distinction entre le défilement lancé par l'utilisateur et le navigateur lancé. Je ne sais pas comment faire cela, mais si je me souviens bien, c'est possible.
mrtsherman
1
Booyah! C'était un problème amusant de fin de soirée. Je dis à mon patron que c'est de ta faute quand je m'endors à mon bureau. Je viens de faire une modification rapide pour supprimer la déclaration de retour. Cela a interféré avec la dissociation que j'ai ajoutée pour l'événement de défilement.
mrtsherman
Au départ, je l'ai fait fonctionner dans un petit fichier d'exemple de base pour le vérifier. Une fois que j'ai confirmé que cela fonctionnait, j'étais déconcerté par le fait que cela ne fonctionnait pas dans mon projet. Grâce au processus d'élimination, j'ai réussi à trouver une déclaration de style unique dans mon fichier css qui le provoquait. C'était l'application d'une police externe. J'ai enveloppé votre code dans une fonction et je le passe maintenant dans un gestionnaire $ (window) .load () dans le gestionnaire doc.ready. Cela semble fonctionner maintenant (avec un léger scintillement de la page initiale). Merci pour le code! Faites-moi savoir si c'est une solution solide ou non.
ThomasReggi
1
Cela ne fonctionnera pas si vous avez du contenu qui se charge après le chargement de la page; Ex: avoir 2 div qui seront remplis d'ajax avec des bannières.
Decebal
@FlashThunder - pouvez-vous définir "ne fonctionne pas"? Publier un message sur la console?
mrtsherman
152

Sur Chrome, même si vous forcez scrollTop à 0, il sautera après le premier événement de défilement.

Vous devez lier le parchemin à ceci:

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

Ainsi, le navigateur est amené à croire qu'il était au début avant l'actualisation.

Josetapadas
la source
5
Bien plus utile que la réponse acceptée si vous ne voulez pas jouer avec le défilement.
Dan Abramov
2
Cela ne fait pas le travail dans Chrome 33. Je veux dire qu'il fait défiler vers le haut avant de charger la nouvelle page. Cependant, le navigateur se souvient toujours de la position de défilement précédente et effectue le même défilement automatique jusqu'à cette position.
Haralan Dobrev
1
Testé sur Chrome 36, Firefox 30 et IE 11. Fonctionne très bien!
Fizzix
24
Pour l'implémentation non-jQuery: window.onbeforeunload = function(){ window.scrollTo(0,0); }
ProfNandaa
5
Pourquoi avez-vous choisi l'événement 'beforeunload' au lieu de 'unload'. Mes tests montrent que ce dernier permet d'éviter de sauter en haut avant que la page ne soit réellement déchargée par le navigateur.
Aleksandr Zonov
76

Pour désactiver la restauration automatique du défilement, ajoutez simplement cette balise à la section head.

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

Il n'est pas pris en charge par IE. Compatibilité du navigateur.

imos
la source
3
Ce serait la meilleure réponse si elle était disponible dans IE / Edge. Vous pouvez voter pour sa mise en œuvre ici: wpdev.uservoice.com/forums/257854-microsoft-edge-developer
The Chewy
4
Cela devrait vraiment être une bonne réponse en 2019. Aucune des autres méthodes ne fonctionne à 100%.
Limbo
2
Peut confirmer que c'est la meilleure solution. Les autres solutions ici ne fonctionnent pas sur Mobile Safari et peuvent être bizarres. Cela fonctionne parfaitement.
user3330820
20

Après un certain nombre d'échecs, j'ai finalement réussi à faire l'affaire. anzo est correct ici car utiliser beforeunloadfera sauter la page en haut lorsqu'un utilisateur recharge la page ou clique sur un lien. Il en unloadva de même pour la manière claire de le faire.

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

Javascript way (Merci ProfNandaa ):

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

EDIT: 16/07/2015

Le problème du saut est toujours là avec Firefox même avec un unloadévénement.

Janaka Dombawela
la source
3
Cette solution est bien meilleure que la beforeunloadsolution car elle évite de sauter en haut de la page lors des recharges et des clics d'ancrage.
BradGreens
@BradGreens Avec Chrome moderne, l'événement onunload est également déclenché lorsque l'utilisateur passe à d'autres onglets, ce qui est inattendu. onbeforeunload est toujours une solution de contournement valide.
Telvin Nguyen
@TelvinNguyen Pouvez-vous donner des ressources à ce sujet? J'ai testé cela sur Google Chrome 72 et fonctionne toujours très bien pour moi.
Janaka Dombawela
@JanakaDombawela Ce que j'ai dit: Le changement d'un nouvel onglet qui poserait problème est incorrect. Cependant, vous pouvez voir que l'événement onunload dans cet exemple ne se déclenche pas correctement, même avec jQuery 1.9.1 vs jQuery 1.8.3. onunload n'est pas fiable. jsfiddle.net/6s4jhdug/3 (1.8.3) jsfiddle.net/frt45ue9 (1.9.1)
Telvin Nguyen
3

Voici une approche plus générale. Au lieu d'essayer d'empêcher le navigateur de défiler (ou de sauter vers le haut comme cela aurait l'air), je restaure simplement la position précédente sur la page. C'est-à-dire que j'enregistre le décalage y actuel de la page dans localStorage et que je fais défiler jusqu'à cette position une fois la page chargée.

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
la source
2

Vous pouvez simplement mettre un # à la fin pour que la page se charge en haut.

Fonctionne sur tous les navigateurs, mobiles et ordinateurs de bureau, car c'est si simple.

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

});

// Ceci charge la page avec un # à la fin.

Daut
la source
Si j'essaie directement sur mon serveur, cela fonctionne comme par magie. Mais, mon cms me donne une erreur de balisage. Je ne peux pas comprendre ce que c'est.
alice le
1
si vous utilisez wordpress changez le $ pour jQuery
Herzling
1

Cela fonctionne pour moi.

    //Reset scroll top

    history.scrollRestoration = "manual"

    $(window).on('beforeunload', function(){
          $(window).scrollTop(0);
    });
Alex s'amuse
la source
-2

Tu devrais être capable de.

Lors du chargement, vérifiez si window.location.hasha une valeur. Si c'est le cas, récupérez l'élément avec un identifiant qui correspond à la valeur de hachage. Recherchez la position de l'élément (appels récursifs à offsetTop / offsetLeft), puis transmettez ces valeurs à la window.scrollTo(x, y)méthode.

Cela devrait faire défiler la page jusqu'à l'élément souhaité.

nikmd23
la source
3
Cela n'empêche pas les navigateurs d'effectuer un défilement automatique. Voilà le sujet de cette question.
Haralan Dobrev