ScrollIntoView () provoquant le déplacement de la page entière


110

J'utilise ScrollIntoView () pour faire défiler l'élément en surbrillance dans une liste. Lorsque je fais défiler vers le bas, ScrollIntoView (false) fonctionne parfaitement. Mais quand je fais défiler vers le haut, ScrollIntoView (true) fait bouger un peu la page entière, ce qui, je pense, est destiné. Existe-t-il un moyen d'éviter le déplacement de la page entière lors de l'utilisation de ScrollIntoView (true)?

Voici la structure de ma page -

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs provient d'un appel ajax. Utilisation de safari mobile.

Merci d'avance pour votre aide!


1
Pouvez-vous fournir un JSFiddle afin que nous puissions voir exactement quel est le problème?
Robert Koritnik

Réponses:


115

Vous pouvez utiliser à la scrollTopplace de scrollIntoView():

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle: http://jsfiddle.net/LEqjm/

S'il y a plus d'un élément défilable que vous souhaitez faire défiler, vous devrez changer le scrollTopde chacun individuellement, en fonction du offsetTops des éléments intermédiaires. Cela devrait vous donner un contrôle précis pour éviter le problème que vous rencontrez.

EDIT: offsetTop n'est pas nécessairement relatif à l'élément parent - il est relatif au premier ancêtre positionné. Si l'élément parent n'est pas positionné (relatif, absolu ou fixe), vous devrez peut-être changer la deuxième ligne en:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;

3
Pour info, cela ne fonctionne que lorsque le parent est en haut de la page. Vous devriez probablement le fairetarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil

2
offsetTop est relatif au parent positionné le plus proche, donc si le nœud parent l'a position: relative, vous ne devez pas soustraire son décalage. Mais vous avez raison dans la plupart des cas.
Brilliand

2
Voici un violon js: jsfiddle.net/LEqjm/258 qui montre également le comportement incorrect de ScrollIntoView.
Rafi

1
@Brilliand merci pour l'idée de position: relativesur prent div: ça résout vraiment le problème
Alex Zhukovskiy

Il fonctionne sur chrome mais il défile un peu plus sur IE, ce qui cache le contenu du texte par le haut. Toute solution @Phil, merci d'avance
Soniya

125

Corrigé avec:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

voir: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
Merci cela a fonctionné. Je n'ai pas compris l'utilisation du bloc et ses valeurs lorsque je l'ai lu. Maintenant qu'il a résolu un problème, je sais ce qu'il fait
Pavan

3
Que signifie «le plus proche»? EDIT: J'ai trouvé une réponse ici: stackoverflow.com/a/48635751/628418
Sammi

Cela a résolu mon problème. Je vois cela se produire dans notre application Web depuis un certain temps, mais il a été difficile de verrouiller la repro. Après avoir ajouté une nouvelle fonctionnalité, cela s'est produit à chaque fois et j'ai pu le retracer jusqu'à cet appel, qui manquait le block : 'nearest'paramètre.
roskelld

Si seulement ils définissaient ce que signifient les valeurs de bloc ... début et plus proche ... c'est tout essai et erreur.
Bae le

Fonctionne avec Chrome, mais pas avec Edge pour moi.
Michael

13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});

ou vous pouvez utilisertop: el['offsetTop']
Junior Mayhé

Cela fonctionne le mieux pour moi. Mais toujours un petit buggy sur Firefox - parfois il s'arrête à mi-chemin de l'élément. Fin sur le bord et le chrome.
Mark

9

J'ai eu ce problème aussi et j'ai passé de nombreuses heures à essayer de le résoudre. J'espère que ma résolution pourra encore aider certaines personnes.

Mon correctif a fini par être:

  • Pour Chrome: passage .scrollIntoView()à .scrollIntoView({block: 'nearest'})(merci à @jfrohn).
  • Pour Firefox: appliquez overflow: -moz-hidden-unscrollable;sur l'élément conteneur qui change.
  • Non testé dans d'autres navigateurs.

8

Jouez avec scrollIntoViewIfNeeded()... assurez-vous qu'il est pris en charge par le navigateur.


1
Je ne savais pas que c'était une chose. Il y a un polyfill
mpen

Dans le document, il est mentionné que ce n'est pas standard mais que cela fonctionne bien. devrions-nous l'utiliser?
Shyam Kumar

8

J'ai ajouté un moyen d'afficher le comportement important du ScrollIntoView - http://jsfiddle.net/LEqjm/258/ [cela devrait être un commentaire mais je n'ai pas assez de réputation]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});

7
Pas une question jQuery.
seangates

6

Le plugin jQuery scrollintoview()augmente la convivialité

Au lieu de l'implémentation DOM par défaut, vous pouvez utiliser un plugin qui anime le mouvement et n'a aucun effet indésirable. Voici la façon la plus simple de l'utiliser avec les valeurs par défaut:

$("yourTargetLiSelector").scrollintoview();

Quoi qu'il en soit, rendez-vous sur ce billet de blog où vous pouvez lire tous les détails et vous obtiendrez éventuellement le code source GitHub du plugin.

Ce plugin recherche automatiquement l'élément ancêtre défilable le plus proche et le fait défiler pour que l'élément sélectionné soit à l'intérieur de son port de vue visible. Si l'élément est déjà dans le port de vue, il ne fait rien bien sûr.


19
@Brilliand: C'est bien sûr vrai, mais cela ne veut pas dire qu'ils ne l'utilisent pas ou qu'ils hésitent à l'utiliser. Je ne fais que proposer une alternative. C'est à OP de décider si c'est une voie qu'ils prendront ou non. Peut-être qu'ils n'ont jamais envisagé d'utiliser jQuery en premier lieu.
Robert Koritnik

Cet OP n'a pas spécifiquement mentionné jQuery est totalement hors de propos: la réponse de @ RobertKoritnik m'a parfaitement servi.
Dave Land

1
Soit dit en passant, Bing affiche votre exemple de code dans les résultats de recherche pour «empêcher l'élément ancêtre de défiler avec scrollintoview». :-)
Dave Land

2

En utilisant l'idée de Brilliant, voici une solution qui ne défile (verticalement) que si l'élément n'est PAS actuellement visible. L'idée est d'obtenir la boîte englobante de la fenêtre et l'élément à afficher dans l'espace de coordonnées de la fenêtre du navigateur. Vérifiez s'il est visible et sinon, faites défiler la distance requise pour que l'élément soit affiché en haut ou en bas de la fenêtre.

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }

2

Ajout de plus d'informations à @Jescopublier.

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methodpour les navigateurs Chrome, Opera, Safari.
    Si l'élément se trouve déjà dans la zone visible de la fenêtre du navigateur, aucun défilement n'a lieu .
  • Element.scrollIntoView() La méthode fait défiler l'élément sur lequel il est appelé dans la zone visible de la fenêtre du navigateur.

Essayez le code ci-dessous dans le mozilla.org scrollIntoView()lien. Publier pour identifier le navigateur

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}

2

dans mon contexte, il pousserait la barre d'outils collante hors de l'écran, ou entrerait à côté d'un bouton fab avec absolu.

en utilisant le plus proche résolu.

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});

1

J'ai eu le même problème, je l'ai résolu en supprimant le transform:translateYCSS que j'ai placé sur footerla page.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.