web-dev-qa-db-fra.com

jQuery - Faire défiler l'élément vers le milieu de l'écran au lieu de le haut avec un lien d'ancrage

Je construis un site d'une page avec une barre de navigation à position fixe qui défile en douceur vers les différents éléments de la section via des liens d'ancrage. Le comportement par défaut pour faire défiler jusqu'à un élément consiste à l'aligner en haut de la fenêtre du navigateur. Au lieu de cela, je veux aligner l'élément au milieu de l'écran.

J'utilise ce balisage pour la navigation:

<nav class="main-nav">
  <a href="#top">Top</a>
  <a href="#section-1">Section 1</a>
  <a href="#section-2">Section 2</a>
  <a href="#section-3">Section 3</a>
  <a href="#section-4">Section 4</a>
  <a href="#section-5">Section 5</a>
</nav>

J'utilise plugin jQuery Smooth Scroll de kswedberg pour lisser le défilement. Je l'initie comme ceci:

$('.main-nav a').smoothScroll({
  offset: 0,
  speed: 700
});

Je souhaite définir le décalage sur ((window).height / 2) - (element height / 2) pour qu'il soit centré verticalement, mais j'ai besoin d'aide pour comprendre comment l'exécuter correctement.

J'en ai besoin pour:

  • Obtenez la hauteur de la fenêtre et divisez-la par deux
  • Obtenez la hauteur de l'élément et divisez-le par deux
  • Soustrayez le premier du second
  • Si possible, alignez-le en haut par défaut si l'élément est plus haut que la fenêtre

Puisqu'il existe de nombreux liens d'ancrage, je suppose que j'ai besoin de vérifier la hauteur de l'élément auquel le lien d'ancrage a été cliqué, ou d'initialiser smoothScroll pour chaque lien d'ancrage.

Est-ce que quelqu'un sait comment faire ça?

33
Nils Kaspersson

L'API fournit un moyen d'exécuter un smoothScroll non lié à un élément. Vous voudrez exécuter cette méthode dans un événement onclick pour les balises d'ancrage afin que vous puissiez avoir accès à sa cible. Ensuite, vous pouvez calculer ce dont vous avez besoin pour atteindre la position souhaitée. Puisque offset est maintenant un décalage absolu au lieu d'un décalage relatif, vous devrez obtenir la position exacte à laquelle faire défiler.

$('.main-nav a').on('click', function(e) { 
  var el = $( e.target.getAttribute('href') );
  var elOffset = el.offset().top;
  var elHeight = el.height();
  var windowHeight = $(window).height();
  var offset;

  if (elHeight < windowHeight) {
    offset = elOffset - ((windowHeight / 2) - (elHeight / 2));
  }
  else {
    offset = elOffset;
  }

  $.smoothScroll({ speed: 700 }, offset);
  return false;
});
33
Steven Lambert

Voici comment le faire avec JQuery ordinaire en utilisant scrollTo ()

 $('.main-nav a').on('click', function(e) { 
  var el = $( e.target.getAttribute('href') );
  var elOffset = el.offset().top;
  var elHeight = el.height();
  var windowHeight = $(window).height();
  var offset;

  if (elHeight < windowHeight) {
    offset = elOffset - ((windowHeight / 2) - (elHeight / 2));
  }
  else {
    offset = elOffset;
  }
  var speed = 700;
  $('html, body').animate({scrollTop:offset}, speed);
});

Ceci est une combinaison du code de straker et du code de cette question: jQuery scrollTo - Center Div in Window Vertically

33
Santiago Angel

Voici un moyen sûr de le faire

var $window = $(window),
    $element = $('.my-element'),
    elementTop = $element.offset().top,
    elementHeight = $element.height(),
    viewportHeight = $window.height(),
    scrollIt = elementTop - ((viewportHeight - elementHeight) / 2);

    $window.scrollTop(scrollIt);
1
ameer nagvenkar

Voici la solution que j'ai finalement utilisée. Cela fonctionne très bien si vous avez un conteneur parent déroulant qui contient tous les éléments qui doivent être centrés lorsque vous cliquez dessus.

N'hésitez pas à exécuter l'extrait de code pour le voir en action!

$('#main-nav a').on('click', function(e) { 
  var el = $(this), parentEl = $('#main-nav');
  
  var elOffset = el.offset().top + parentEl.scrollTop();
  var elHeight = el.height();
  var parentHeight = parentEl.height();
  
  var offset = elOffset - ((parentHeight - elHeight) / 2);
 
  parentEl.animate({scrollTop:offset}, 700);
});
#main-nav {
  height: 200px;
  width: 200px;
  outline: 1px solid red;
  overflow: hidden;
}

#main-nav a {
  height: 50px;
  background: blue;
  display: block;
  margin-bottom: 5px;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav id="main-nav">
  <a href="#top">Top</a>
  <a href="#section-1">Section 1</a>
  <a href="#section-2">Section 2</a>
  <a href="#section-3">Section 3</a>
  <a href="#section-4">Section 4</a>
  <a href="#section-5">Section 5</a>
  <a href="#section-6">Section 6</a>
  <a href="#section-7">Section 7</a>
  <a href="#section-8">Section 8</a>
  <a href="#section-9">Section 9</a>
  <a href="#section-10">Section 10</a>
</nav>
0
Andy