Dans ce tutoriel nous allons voir comment écouter le scroll d'une page afin d'activer l'élément du menu correspondant. C'est une technique indispensable qui est très utilisé sur les sites "one page" mais aussi pour créer des sommaires dynamiques.
Le fonctionnement
Afin d'identifier les éléments à observer on utilisera un attribut data-spy
. Chaque élément aura aussi un id
qui sera utilisé par les liens du menu.
<nav>
<a href="#section1">Section 1</a>
<a href="#section2">Section 2</a>
<a href="#section3">Section 3</a>
<a href="#section4">Section 4</a>
<a href="contact.html">Contact</a>
</nav>
<main>
<section id="section1" data-spy>Section 1</section>
<section id="section2" data-spy>Section 2</section>
<section id="section3" data-spy>Section 3</section>
<section id="section4" data-spy>Section 4</section>
</main>
Ensuite on utilisera l'IntersectionObserver afin de trouver quelle section est visible à l'écran. Afin de simplifier la détection de l'élément on va chercher à obtenir l'intersection avec une barre de 1px situé à 40% de hauteur (en jouant sur le rootMargin).
const y = Math.round(window.innerHeight * ratio)
const observer = new IntersectionObserver(callback, {
rootMargin: `-${window.innerHeight - y - 1}px 0px -${y}px 0px`
})
Dans le callback on activera l'élément visible à l'écran
const callback = function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
activate(entry.target)
}
})
}
const activate = function (elem) {
const id = elem.getAttribute('id')
const anchor = document.querySelector(`a[href="#${id}"]`)
if (anchor === null) {
return null
}
anchor.parentElement
.querySelectorAll('.active')
.forEach(node => node.classList.remove('active'))
anchor.classList.add('active')
}
On adaptera la fonction activate
en fonction de la situation.