91 votes

Empêcher le défilement du navigateur sur l'historique HTML5

Est-il possible de prévenir le comportement par défaut de défilement du document, lors d'un événement popstate se produit?

Notre site utilise jQuery animation de défilement et de History.js et les modifications de l'état devrait faire défiler l'utilisateur dans les différentes zones de la page, que ce soit via pushstate ou popstate. Le problème, c'est le navigateur restaure la position de défilement de l'état précédent automatiquement lorsqu'un événement popstate se produit.

J'ai essayé à l'aide d'un élément de conteneur à 100% de la largeur et de la hauteur du document et faire défiler le contenu à l'intérieur de ce conteneur. Le problème avec ce que j'ai trouvé est qu'il ne semble pas être aussi lisse que le défilement du document; surtout si vous utilisez beaucoup de css3 comme une boîte-ombres et les dégradés.

J'ai aussi essayé de stocker le document de position de défilement lors d'une initiées par l'utilisateur de faire défiler et de les restaurer une fois le navigateur fait défiler la page (sur popstate). Cela fonctionne très bien dans Firefox 12, mais dans Chrome 19 il y a un scintillement dû à la page défile et restauré. Je suppose que c'est à faire avec un temps de retard entre le rouleau et le rouleau cas de feu (d'où la position de défilement est rétabli).

Firefox fait défiler la page (et les feux de l'événement scroll) avant popstate feux de Chrome et les feux de popstate d'abord, puis fait défiler le document.

Tous les sites que j'ai vu qui utilisent l'API de l'histoire soit utiliser une solution similaire à ceux ci-dessus ou tout simplement ignorer la position de défilement de changer lorsqu'un utilisateur passe en arrière/vers l'avant (par exemple, GitHub).

Est-il possible de prévenir le document défile sur popstate événements?

33voto

Beat Richartz Points 5569

Cela a été une question avec le mozilla developer de base depuis plus d'un an maintenant. Malheureusement, le billet n'a pas vraiment de progrès. Je pense que Chrome est le même: Il n'y a aucun moyen fiable de s'attaquer à la position de défilement onpopstate via js, puisqu'il est natif le comportement du navigateur.

Il y a de l'espoir pour l'avenir, cependant, si vous regardez l' historique HTML5 spec, qui stipule explicitement que les voeux pour la position de défilement à être représentés sur l'état de l'objet:

L'histoire de ces objets représentent leur contexte de navigation de l'historique de session, comme un plat de la liste de l'historique de session entrées. Chaque session histoire de l'entrée se compose d'une URL et éventuellement un objet d'état, et peut en outre avoir un titre, un objet Document, les données de formulaire, une position de défilement, et d'autres informations associées.

Cela, et si vous lisez les commentaires sur mozilla billet mentionné ci-dessus, permet de penser qu'il est possible que dans un avenir proche, la position de défilement ne pourra plus être restaurée onpopstate, au moins pour les personnes utilisant pushState.

Malheureusement, jusqu'alors, la position de défilement est mémorisé lors de l' pushState est utilisé, et replaceState ne remplace pas la position de défilement. Sinon, il serait assez facile, et vous pouvez utiliser replaceState pour régler la position de Défilement à chaque fois que l'utilisateur a fait défiler la page (avec une certaine prudence onscroll gestionnaire).

Aussi, malheureusement, la spec HTML5 ne précise pas quand exactement l' popstate événement doit être mis le feu, il dit seulement: «est déclenché, dans certains cas, lorsque vous accédez à un historique de la session d'entrée», qui n'a clairement pas dire si c'est avant ou après; si elle était toujours devant, une solution à la manipulation de la faire défiler événement survenant après la popstate serait possible.

Annuler l'événement scroll?

En outre, il serait aussi facile, si l'événement scroll où annulable, il ne l'est pas. Si elle l'est, vous pouvez simplement annuler le premier événement scroll d'une série (l'utilisateur de faire défiler les événements sont comme des lemmings, ils viennent dans des dizaines, alors que le défilement de l'événement déclenché par l'histoire de repositionnement est un seul), et vous serez amende.

Il n'y a pas de solution pour l'instant

Autant que je le vois, la seule chose que je vous recommande pour le moment est d'attendre la Spec HTML5 pour être pleinement mis en œuvre et de rouler avec le comportement du navigateur dans ce cas, que signifie: animer le défilement lorsque le navigateur vous permet de le faire, et laisser le navigateur repositionner la page quand il y a une histoire de l'événement. La seule chose que vous pouvez influencer la position sage, c'est que vous utilisez pushState lorsque la page est placé dans une bonne façon d'aller. Toute autre solution est soit lié à avoir des bugs, ou trop spécifiques à un navigateur, ou les deux.

4voto

Nathan MacInnes Points 6749

Vous allez avoir à utiliser une sorte d'horrible browser sniffing ici. Pour Firefox, je voudrais aller avec votre solution de stockage de la position de défilement et de la restauration.

Je pensais que j'avais une bonne solution à base de Webkit sur votre description, mais j'ai juste essayé en Chrome 21, et il semble que Chrome défile d'abord, puis déclenche l'événement popstate, puis déclenche l'événement scroll. Mais pour référence, voici ce que j'ai trouvé:

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

La magie noire comme prétendant à la page défile par le déplacement d'un absolute positionné élément est exclu par l'écran de repeindre la vitesse aussi.

Donc, je suis sûr à 99% que la réponse est que vous ne pouvez pas, et vous allez avoir à utiliser l'un des compromis que vous avez mentionné dans la question. Les deux navigateurs de défilement avant de JavaScript ne sait rien à ce sujet, de sorte que le JavaScript ne peut que réagir après l'événement. La seule différence est que Firefox n'est pas peindre l'écran jusqu'à ce que après le Javascript a tiré, qui est pourquoi il y a une solution viable dans Firefox, mais pas dans WebKit.

2voto

mshipov Points 1

La solution consiste à utiliser position: fixed et à spécifier top égal à la position de défilement de la page.

Voici un exemple:

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

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

Oui, vous recevez une barre de défilement clignotante, mais elle est moins perverse.

0voto

Prashant Saraswat Points 361

Créez un élément 'span' quelque part en haut de la page et définissez le focus sur ceci au chargement. Le navigateur fera défiler jusqu'à l'élément ciblé. Je comprends que ceci est une solution de contournement et se concentrer sur «span» ne fonctionne pas dans tous les navigateurs (uhmmm .. Safari). J'espère que cela t'aides.

0voto

geo1701 Points 3269

Voici ce que j'ai implémenté sur un site qui souhaitait que la position du défilement se concentre sur un élément spécifique lorsque la poststate est déclenchée (bouton Précédent):

 $(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');
}
 

Testé et fonctionne sous firefox.

Chrome fera défiler jusqu'à la position, puis se repositionnera à son emplacement d'origine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X