web-dev-qa-db-fra.com

scrollIntoView Scrolls juste trop loin

J'ai une page où une barre de défilement contenant des lignes de table avec divs en eux est générée dynamiquement à partir de la base de données. Chaque ligne de la table agit comme un lien, un peu comme si vous lisiez une liste de lecture YouTube à côté du lecteur vidéo.

Lorsqu'un utilisateur visite la page, l'option sur laquelle il se trouve est censée aller en haut du div. Cette fonctionnalité fonctionne. Le problème est que cela va un peu trop loin. Comme si l'option sur laquelle ils sont est environ 10px trop élevé. Ainsi, la page est visitée, l'URL est utilisée pour identifier quelle option a été sélectionnée, puis fait défiler cette option vers le haut du div. Note: Ce n'est pas la barre de défilement pour la fenêtre, c'est un div avec une barre de défilement.

J'utilise ce code pour le faire déplacer l'option sélectionnée en haut de la div:

var pathArray = window.location.pathname.split( '/' );

var el = document.getElementById(pathArray[5]);

el.scrollIntoView(true);

Il le déplace vers le haut de la division, mais environ 10 pixels de trop .. .. Quelqu'un sait comment résoudre ce problème?

35
Matthew Wilson

S'il s'agit d'environ 10 pixels, vous pouvez simplement ajuster manuellement le décalage de défilement contenant div comme suit:

el.scrollIntoView(true);
document.getElementById("containingDiv").scrollTop += 10;
30
Lucas Trzesniewski

Vous pouvez le faire en deux étapes:

el.scrollIntoView(true);
window.scrollBy(0, -10); // Adjust scrolling with a negative value here
45
fred727

Défiler en douceur à la bonne position

Il vous suffit d’obtenir la coordonnée correcteY et d’utiliser window.scrollTo

const yourElement = document.getElementById('profilePhoto');
const yCoordinate = yourElement.getBoundingClientRect().top + window.pageYOffset;
const yOffset = -10; 

window.scrollTo({
    top: yCoordinate + yOffset,
    behavior: 'smooth'
});
19
Arseniy-II

Ancre de position par méthode absolue

Pour ce faire, vous pouvez également placer vos ancres exactement où vous le souhaitez sur la page au lieu de vous fier au défilement par décalage. Je trouve que cela permet un meilleur contrôle de chaque élément (par exemple, si vous souhaitez un décalage différent pour certains éléments), et peut également être plus résistant aux modifications/différences des API de navigateur.

<div id="title-element" style="position: relative;">
  <div id="anchor-name" style="position: absolute; top: -100px; left: 0" />
</div>

Maintenant, le décalage est spécifié sous la forme -100px par rapport à l'élément. Créez une fonction pour créer cette ancre en vue de la réutilisation du code. Si vous utilisez un framework JS moderne tel que React, créez un composant qui restitue votre ancre, puis transmettez le nom de l'ancre et l'alignement de chaque ne pas être le même.

Ensuite, utilisez simplement:

const element = document.getElementById('anchor-name')
element.scrollIntoView({ behavior: 'smooth', block: 'start' });

Pour un défilement régulier avec un décalage de 100px.

16
Steve Banton

Vous pouvez également utiliser les options element.scrollIntoView()

el.scrollIntoView(
  { 
    behavior: 'smooth', 
    block: 'start' 
  },
);

dont la plupart des navigateurs support

7
Nicholas Murray

En supposant que vous souhaitiez faire défiler les divs qui sont tous au même niveau dans DOM et ont le nom de classe "scroll-with-offset", alors ce CSS résoudra le problème:

.scroll-with-offset {    
  padding-top: 100px;
  margin-bottom: -100px;
}

Le décalage par rapport au haut de la page est de 100 pixels. Il ne fonctionnera comme prévu qu'avec le bloc: 'start': 

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

Ce qui se passe, c’est que le point le plus haut des divs est à l’emplacement normal mais que leur contenu interne commence 100px au-dessous de l’emplacement normal. C'est à ça que sert padding-top: 100px. margin-bottom: -100px sert à compenser la marge supplémentaire des divs ci-dessous . Pour compléter la solution, ajoutez également ce CSS afin de compenser les marges/paddings des divs les plus en haut et les plus bas:

.top-div {
  padding-top: 0;
}
.bottom-div {
  margin-bottom: 0;
}
3
George P

En me basant sur une réponse précédente, je le fais dans un projet Angular5.

Commencé avec:

// el.scrollIntoView(true);
el.scrollIntoView({
   behavior: 'smooth',
   block: 'start'
});
window.scrollBy(0, -10); 

Mais cela posait quelques problèmes et nécessitait de définir timeTimeout pour le scrollBy () comme ceci:

//window.scrollBy(0,-10);
setTimeout(() => {
  window.scrollBy(0,-10)
  }, 500);

Et cela fonctionne parfaitement dans MSIE11 et Chrome 68+. Je n'ai pas testé en FF. 500 ms était le plus court délai dans lequel je m'aventurerais. Aller plus bas a parfois échoué car le défilement lisse n’était pas encore terminé. Ajustez au besoin pour votre propre projet.

+1 à Fred727 pour cette solution simple mais efficace.

3
PrimaryW

J'ai ceci et cela fonctionne brillamment pour moi:

// add a smooth scroll to element
scroll(el) {
el.scrollIntoView({
  behavior: 'smooth',
  block: 'start'});

setTimeout(() => {
window.scrollBy(0, -40);
}, 500);}

J'espère que ça aide.

1
Fernando Brandao

La solution la plus simple qui fonctionne pour moi:

 $('html, body').animate({ scrollTop: $(yourElement).offset().top - 20}, 800);
0
Offir Pe'er

Cela fonctionne pour moi dans Chrome (avec un défilement régulier et aucun piratage temporel)

Il déplace simplement l'élément, lance le défilement, puis le déplace vers l'arrière.

Il n'y a pas de "popping" visible si l'élément est déjà à l'écran.

pos = targetEle.style.position;
top = targetEle.style.top;
targetEle.style.position = 'relative';
targetEle.style.top = '-20px';
targetEle.scrollIntoView({behavior: 'smooth', block: 'start');
targetEle.style.top = top;
targetEle.style.position = pos;
0
Ryan How

Mon idée principale est de créer un tempDiv au-dessus de la vue vers laquelle nous voulons faire défiler. Cela fonctionne bien sans retarder mon projet.

scrollToView = (element, offset) => {
    var rect = element.getBoundingClientRect();
    var targetY = rect.y + window.scrollY - offset;

    var tempDiv;
    tempDiv = document.getElementById("tempDiv");
    if (tempDiv) {
        tempDiv.style.top = targetY + "px";
    } else {
        tempDiv = document.createElement('div');
        tempDiv.id = "tempDiv";
        tempDiv.style.background = "#F00";
        tempDiv.style.width = "10px";
        tempDiv.style.height = "10px";
        tempDiv.style.position = "absolute";
        tempDiv.style.top = targetY + "px";
        document.body.appendChild(tempDiv);
    }

    tempDiv.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

Exemple d'utilisation

onContactUsClick = () => {
    this.scrollToView(document.getElementById("contact-us"), 48);
}

J'espère que ça aide

0
Phan Van Linh