J'ai ce code pour mon site Web

function clickMe() {
   var element = document.getElementById('about');
   element.scrollIntoView({
       block: "start",
       behavior: "smooth",
   });
}

Cela fonctionne assez bien mais j'ai un en-tête fixe, donc lorsque le code défile jusqu'à l'élément, l'en-tête est gênant.

Existe-t-il un moyen d'avoir un décalage et de le faire défiler en douceur?

28
Tim Wijma 13 avril 2018 à 18:03

5 réponses

Meilleure réponse

Existe-t-il un moyen d'avoir un décalage et de le faire défiler en douceur?

Oui, mais pas avec scrollIntoView ()

Les scrollIntoViewOptions de Element.scrollIntoView () ne vous permettez pas d'utiliser un décalage. Il est uniquement utile lorsque vous souhaitez faire défiler jusqu'à la position exacte de l'élément.

Vous pouvez cependant utiliser Window.scrollTo () avec des options pour faire défiler jusqu'à une position décalée et pour le faire en douceur .

Si vous avez un en-tête d'une hauteur de 30px par exemple, vous pouvez effectuer les opérations suivantes:

function scrollToTargetAdjusted(){
    var element = document.getElementById('targetElement');
    var headerOffset = 45;
    var elementPosition = element.getBoundingClientRect().top;
    var offsetPosition = elementPosition - headerOffset;

    window.scrollTo({
         top: offsetPosition,
         behavior: "smooth"
    });
}

Cela défilera en douceur jusqu'à votre élément afin qu'il ne soit pas bloqué par votre en-tête.

Remarque : vous soustrayez le décalage car vous voulez vous arrêter avant de faire défiler votre en-tête sur votre élément.

Voyez-le en action

Vous pouvez comparer les deux options dans l'extrait ci-dessous.

<script type="text/javascript">
  function scrollToTarget() {

    var element = document.getElementById('targetElement');
    element.scrollIntoView({
      block: "start",
      behavior: "smooth",
    });
  }

  function scrollToTargetAdjusted() {
    	var element = document.getElementById('targetElement');
      var headerOffset = 45;
    	var elementPosition = element.getBoundingClientRect().top;
      var offsetPosition = elementPosition - headerOffset;
      
      window.scrollTo({
          top: offsetPosition,
          behavior: "smooth"
      });   
  }

  function backToTop() {
    window.scrollTo(0, 0);
  }
</script>

<div id="header" style="height:30px; width:100%; position:fixed; background-color:lightblue; text-align:center;"> <b>Fixed Header</b></div>

<div id="mainContent" style="padding:30px 0px;">

  <button type="button" onclick="scrollToTarget();">element.scrollIntoView() smooth, header blocks view</button>
  <button type="button" onclick="scrollToTargetAdjusted();">window.scrollTo() smooth, with offset</button>

  <div style="height:1000px;"></div>
  <div id="targetElement" style="background-color:red;">Target</div>
  <br/>
  <button type="button" onclick="backToTop();">Back to top</button>
  <div style="height:1000px;"></div>
</div>
31
Søren D. Ptæus 17 avril 2018 à 10:11

Je sais que c'est un hack et c'est certainement quelque chose que vous devez utiliser avec prudence, mais vous pouvez réellement ajouter un padding et un margin négatif à l'élément. Je ne peux pas garantir que cela fonctionnerait pour vous car je n'ai pas votre balisage et votre code, mais j'ai eu un problème similaire et j'ai utilisé cette solution de contournement pour le résoudre.

Supposons que votre en-tête soit 30px et que vous souhaitez un décalage de 15px, puis:

  #about {
     padding-top: 45px; // this will allow you to scroll 15px below your 30px header
     margin-top: -45px; // and this will make sure that you don't change your layout because of it
  }
0
Yulian 6 mars 2020 à 14:28

La réponse de Søren D. Ptæus m'a mis sur la bonne voie mais j'ai eu des problèmes avec getBoundingClientRect() quand je n'étais pas au sommet du window.

Ma solution ajoute un peu plus à la sienne pour que getBoundingClientRect() fonctionne un peu plus régulièrement et avec plus de polyvalence. J'ai utilisé l'approche décrite ici et l'ai mise en œuvre pour faire fonctionner cela comme prévu.

const element = document.getElementById('targetElement');
const offset = 45;
const bodyRect = document.body.getBoundingClientRect().top;
const elementRect = element.getBoundingClientRect().top;
const elementPosition = elementRect - bodyRect;
const offsetPosition = elementPosition - offset;

window.scrollTo({
  top: offsetPosition,
  behavior: 'smooth'
});

Exemple de Codepen

N'oubliez pas d'inclure le polyfill lors de l'implémentation!

39
Insane 12 juin 2018 à 21:10

J'ai essayé les autres solutions, mais j'avais un comportement étrange. Cependant, cela a fonctionné pour moi.

function scrollTo(id) {
    var element = document.getElementById(id);
    var headerOffset = 60;
    var elementPosition = element.offsetTop;
    var offsetPosition = elementPosition - headerOffset;
    document.documentElement.scrollTop = offsetPosition;
    document.body.scrollTop = offsetPosition; // For Safari
}

Et le style:

html {
    scroll-behavior: smooth;
}
2
Felipe Cupido Iñiguez 21 avril 2019 à 17:13

Solution simple mais élégante si l'élément a une petite hauteur (plus courte que la fenêtre):

element.scrollIntoView({ behavior: 'instant', block: 'center' });

Le block: center fera défiler l'élément de sorte que le centre de l'élément soit au centre vertical de la fenêtre, de sorte que l'en-tête supérieur ne le couvrira pas.

2
coreyward 14 févr. 2020 à 01:50