getBoundingClientRect
Méthode pour animer explicitement la bordure entre les éléments de la barre de navigation lorsqu’ils sont cliqués. La deuxième approche réalise les mêmes fonctionnalités en utilisant l’API de transition de la nouvelle vue.
J’ai récemment rencontré un vieux tutoriel jQuery démontrant un Bar de navigation «Moving Highlight» et a décidé que le concept était dû pour une mise à niveau moderne. Avec ce modèle, la bordure autour de l’élément de navigation actif se crée directement d’un élément à un autre lorsque l’utilisateur clique sur les éléments du menu. En 2025, nous avons de bien meilleurs outils pour manipuler le DOM via Vanilla JavaScript. De nouvelles fonctionnalités comme le Voir l’API de transition Rendre une amélioration progressive plus facilement et gérer une grande partie de l’animation minuties.
Dans ce didacticiel, je vais démontrer deux méthodes de création de la barre de navigation «Moving Highlight» à l’aide de Plain JavaScript et CSS. Le premier exemple utilise le getBoundingClientRect
Méthode pour animer explicitement la bordure entre les éléments de la barre de navigation lorsqu’ils sont cliqués. Le deuxième exemple atteint la même fonctionnalité à l’aide de l’API de transition de la nouvelle vue.
Le balisage initial
Supposons que nous avons une application à une seule page où le contenu change sans que la page soit rechargée. Le HTML et le CSS de départ sont votre barre de navigation standard avec un div
élément contenant un id
de #highlight
. Nous donnons au premier élément de navigation une classe de .active
.
Voir le stylo [Moving Highlight Navbar Starting Markup [forked]](https://codepen.io/smashingmag/pen/eajqybw) par Blake Lundquist.
Pour cette version, nous positionnerons le #highlight
élément autour de l’élément avec le .active
classe pour créer une bordure. Nous pouvons utiliser absolute
Positionnement et animer l’élément à travers la barre de navigation pour créer l’effet souhaité. Nous le cacherons initialement hors écran en ajoutant left: -200px
et inclure transition
Styles pour toutes les propriétés afin que les changements de position et de taille de l’élément se produisent progressivement.
#highlight {
z-index: 0;
position: absolute;
height: 100%;
width: 100px;
left: -200px;
border: 2px solid green;
box-sizing: border-box;
transition: all 0.2s ease;
}
Ajouter un gestionnaire d’événements de la passe-partout pour les interactions de clics
Nous voulons que l’élément de surbrillance s’anime lorsqu’un utilisateur modifie le .active
élément de navigation. Ajoutons un click
gestionnaire d’événements au nav
élément, puis filtrez les événements causés uniquement par des éléments correspondant à notre sélecteur souhaité. Dans ce cas, nous voulons seulement changer le .active
Élément de navigation si l’utilisateur clique sur un lien qui n’a pas déjà le .active
classe.
Initialement, nous pouvons appeler console.log
Pour s’assurer que le gestionnaire ne tire uniquement à l’attente:
const navbar = document.querySelector('nav');
navbar.addEventListener('click', function (event) {
// return if the clicked element doesn't have the correct selector
if (!event.target.matches('nav a:not(active)')) {
return;
}
console.log('click');
});
Ouvrez votre console de navigateur et essayez de cliquer sur différents éléments dans la barre de navigation. Tu ne devrais voir que "click"
être enregistré lorsque vous sélectionnez un nouvel élément dans la barre de navigation.
Maintenant que nous savons que notre gestionnaire d’événements travaille sur les éléments corrects, ajoutons du code pour déplacer le .active
classe de l’élément de navigation qui a été cliqué. Nous pouvons utiliser l’objet transmis dans le gestionnaire d’événements pour trouver l’élément qui a initialisé l’événement et donner à cet élément une classe de .active
Après l’avoir retiré de l’élément précédemment actif.
const navbar = document.querySelector('nav');
navbar.addEventListener('click', function (event) {
// return if the clicked element doesn't have the correct selector
if (!event.target.matches('nav a:not(active)')) {
return;
}
- console.log('click');
+ document.querySelector('nav a.active').classList.remove('active');
+ event.target.classList.add('active');
});
Notre #highlight
L’élément doit se déplacer à travers la barre de navigation et se positionner autour de l’élément actif. Écrivons une fonction pour calculer une nouvelle position et une nouvelle largeur. Depuis le #highlight
Le sélecteur a transition
Styles appliqués, il se déplacera progressivement lorsque sa position changera.
En utilisant getBoundingClientRect
nous pouvons obtenir des informations sur la position et la taille d’un élément. Nous calculons la largeur de l’élément de navigation actif et son décalage à partir de la limite gauche de l’élément parent. Ensuite, nous attribuons des styles à l’élément de surbrillance afin que sa taille et sa position correspondent.
// handler for moving the highlight
const moveHighlight = () => {
const activeNavItem = document.querySelector('a.active');
const highlighterElement = document.querySelector('#highlight');
const width = activeNavItem.offsetWidth;
const itemPos = activeNavItem.getBoundingClientRect();
const navbarPos = navbar.getBoundingClientRect()
const relativePosX = itemPos.left - navbarPos.left;
const styles = {
left: `${relativePosX}px`,
width: `${width}px`,
};
Object.assign(highlighterElement.style, styles);
}
Appelons notre nouvelle fonction lorsque l’événement de clic tire:
navbar.addEventListener('click', function (event) {
// return if the clicked element doesn't have the correct selector
if (!event.target.matches('nav a:not(active)')) {
return;
}
document.querySelector('nav a.active').classList.remove('active');
event.target.classList.add('active');
+ moveHighlight();
});
Enfin, appelons également la fonction immédiatement afin que la bordure se déplace derrière notre élément actif initial lorsque la page se charge d’abord:
// handler for moving the highlight
const moveHighlight = () => {
// ...
}
// display the highlight when the page loads
moveHighlight();
Maintenant, la frontière se déplace à travers la barre de navigation lorsqu’un nouvel élément est sélectionné. Essayez de cliquer sur les différents liens de navigation pour animer la barre de navigation.
Voir le stylo [Moving Highlight Navbar [forked]](https://codepen.io/smashingmag/pen/wbvmxqv) par Blake Lundquist.
Cela n’a pris que quelques lignes de JavaScript de vanille et pourrait facilement être étendu pour tenir compte d’autres interactions, comme mouseover
événements. Dans la section suivante, nous explorerons la refactorisation de cette fonction à l’aide de l’API de transition View.
Utilisation de l’API de transition View
L’API de transition View fournit des fonctionnalités pour créer des transitions animées entre les vues du site Web. Sous le capot, l’API crée des instantanés de vues «avant» et «après», puis gère la transition entre elles. Les transitions de vision sont utiles pour créer des animations entre les documents, fournissant Expérience utilisateur native-application en vedette dans des frameworks comme Astron. Cependant, l’API fournit également des gestionnaires destinés à Applications de style spa. Nous l’utiliserons pour réduire le JavaScript nécessaire dans notre implémentation et créer plus facilement des fonctionnalités de secours.
Pour cette approche, nous n’avons plus besoin d’un #highlight
élément. Au lieu de cela, nous pouvons styliser le .active
Élément de navigation directement à l’aide de pseudo-sélecteurs et laissez l’API de transition View gérer l’animation entre les états d’interface utilisateur avant et après lorsqu’un nouvel élément de navigation est cliqué.
Nous allons commencer par nous débarrasser du #highlight
élément et son CSS associé et le remplacer par des styles pour le nav a::after
Pseudo-sélectionneur:
<nav>
- <div id="highlight"></div>
<a href="#" class="active">Home</a>
<a href="#services">Services</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
- #highlight {
- z-index: 0;
- position: absolute;
- height: 100%;
- width: 0;
- left: 0;
- box-sizing: border-box;
- transition: all 0.2s ease;
- }
+ nav a::after {
+ content: " ";
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ border: none;
+ box-sizing: border-box;
+ }
Pour .active
classe, nous incluons le view-transition-name
propriété, déverrouillant ainsi la magie de l’API de transition de la vue. Une fois que nous déclencherons la transition de la vue et modifiez l’emplacement du .active
L’article de navigation dans les instantanés DOM, «avant» et «après» sera pris, et le navigateur animera la frontière à travers la barre. Nous donnerons à notre avis Transition le nom de highlight
mais nous pourrions théoriquement lui donner n’importe quel nom.
nav a.active::after {
border: 2px solid green;
view-transition-name: highlight;
}
Une fois que nous avons un sélecteur qui contient un view-transition-name
propriété, la seule étape restante consiste à déclencher la transition en utilisant le startViewTransition
Méthode et passer dans une fonction de rappel.
const navbar = document.querySelector('nav');
// Change the active nav item on click
navbar.addEventListener('click', async function (event) {
if (!event.target.matches('nav a:not(.active)')) {
return;
}
document.startViewTransition(() => {
document.querySelector('nav a.active').classList.remove('active');
event.target.classList.add('active');
});
});
Ci-dessus est une version révisée du click
gestionnaire. Au lieu de faire tous les calculs pour la taille et la position de la bordure en mouvement nous-mêmes, l’API de transition View gère tout cela pour nous. Nous avons seulement besoin d’appeler document.startViewTransition
et passer une fonction de rappel pour modifier l’élément qui a le .active
classe!
Ajustement de la transition de vue
À ce stade, en cliquant sur un lien de navigation, vous remarquerez que la transition fonctionne, mais certains problèmes de dimensionnement étrange sont visibles.
Cette incohérence de dimensionnement est causée par des changements de rapport d’aspect au cours de la transition de la vue. Nous n’irons pas dans les détails ici, mais Jake Archibald a une explication détaillée que vous pouvez lire pour plus d’informations. Bref, pour garantir que la hauteur de la frontière reste uniforme tout au long de la transition, nous devons déclarer un height
pour ::view-transition-old
et ::view-transition-new
Les pseudo-sélecteurs représentant respectivement un instantané statique de l’ancienne et nouvelle vue.
::view-transition-old(highlight) {
height: 100%;
}
::view-transition-new(highlight) {
height: 100%;
}
Faisons une refactorisation finale pour ranger notre code en déplaçant le rappel vers une fonction distincte et en ajoutant une repli pour le moment où les transitions ne sont pas prises en charge:
const navbar = document.querySelector('nav');
// change the item that has the .active class applied
const setActiveElement = (elem) => {
document.querySelector('nav a.active').classList.remove('active');
elem.classList.add('active');
}
// Start view transition and pass in a callback on click
navbar.addEventListener('click', async function (event) {
if (!event.target.matches('nav a:not(.active)')) {
return;
}
// Fallback for browsers that don't support View Transitions:
if (!document.startViewTransition) {
setActiveElement(event.target);
return;
}
document.startViewTransition(() => setActiveElement(event.target));
});
Voici notre point de vue de navigation à transition! Observez la transition en douceur lorsque vous cliquez sur les différents liens.
Voir le stylo [Moving Highlight Navbar with View Transition [forked]](https://codepen.io/smashingmag/pen/ogxelke) par Blake Lundquist.
Conclusion
Les animations et les transitions entre les états d’interface utilisateur du site Web nécessitaient de nombreux kilobytes de bibliothèques externes, ainsi que du code verbeux, déroutant et sujet, mais Vanilla JavaScript et CSS ont depuis incorporé des fonctionnalités pour atteindre Interactions natives-applicables sans se ruiner. Nous l’avons démontré en mettant en œuvre le modèle de navigation de «recours en mouvement» en utilisant deux approches: les transitions CSS combinées avec le getBoundingClientRect()
Méthode et API de transition View.
Ressources
(GG, YK)
Source link