Cet atelier de programmation vous explique comment créer un composant de mise en page de navigation latérale coulissante et réactive sur le Web. Nous allons créer le composant au fur et à mesure, en commençant par HTML, puis CSS et enfin JavaScript.
Consultez mon article de blog Créer un composant Sidenav pour en savoir plus sur les fonctionnalités de la plate-forme Web CSS choisies pour créer ce composant.
Configuration
- Cliquez sur Remix to Edit (Remixer pour modifier) pour rendre le projet modifiable.
- Ouvrez
app/index.html
.
HTML
Commencez par configurer les éléments HTML essentiels pour avoir du contenu et des boîtes sur lesquelles travailler.
Collez le code HTML suivant dans la balise <body>
.
<aside></aside>
<main></main>
<aside>
contient le menu de navigation en tant qu'élément complémentaire de <main>
, qui contient le contenu principal de la page.
Nous allons ensuite remplir ces éléments sémantiques avec le reste du contenu de la page.
Ajoutez un élément de navigation, des liens de navigation et un lien de fermeture à l'intérieur de l'élément <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
Les liens sont parfaits dans les éléments <nav>
, et les éléments <nav>
sont parfaits dans les barres latérales <aside>
.
Toutefois, nous pouvons encore améliorer notre service.
Dans l'élément de contenu principal, ajoutez un en-tête et un article pour contenir sémantiquement le contenu de la mise en page.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
L'en-tête contient le lien permettant d'ouvrir le menu. L'élément aside comporte le bouton de fermeture. Nous allons bientôt afficher et masquer des éléments en fonction de la taille de la fenêtre d'affichage.
Dans l'élément <article>
, nous avons collé une phrase d'espace réservé. Remplacez `` par votre propre contenu ou collez le lorem fourni ci-dessous :
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
Ce contenu et sa longueur sont ce qui rendra la page défilable lorsqu'elle dépassera la hauteur de votre fenêtre d'affichage.
Jusqu'à présent, vous avez ajouté un élément aside, avec une navigation, des liens et un moyen de fermer la navigation latérale. Vous avez également ajouté un en-tête, un moyen d'ouvrir la navigation latérale et un article à l'élément principal. Ce code est propre, sémantique et déjà assez intemporel, mais nous pouvons le rendre encore plus propre et plus clair pour tout le monde. Le lien "Ouvrir" dans le panneau latéral pourrait être plus clairement indiqué.
Ajoutez les attributs title
et aria-label
à l'élément de lien d'ouverture de l'en-tête :
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
L'icône SVG ouverte pourrait également être plus clairement indiquée. Ajoutez les attributs suivants au SVG à l'intérieur de l'élément de lien ouvert :
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
Le lien de fermeture dans le panneau latéral pourrait être plus clairement indiqué.
Ajoutez les attributs title
et aria-label
à l'élément de lien de fermeture de la navigation latérale :
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
Il est temps de mettre en page les éléments. Le contenu principal et la sidenav sont des enfants directs de la balise <body>
. C'est donc un bon point de départ.
Ajoutez le CSS suivant dans css/sidenav.css
afin que l'élément <body>
dispose les enfants.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
Cette mise en page indique essentiellement : créez une ligne nommée stack
avec tout ce qu'elle contient, et deux colonnes dans cette ligne, dont la deuxième est également nommée stack
. La première colonne doit être dimensionnée en fonction de ses besoins de contenu minimaux, et la deuxième colonne peut occuper le reste de l'espace.
Ensuite, si la fenêtre d'affichage est limitée à 540px
ou moins, placez les éléments de contenu principal et de navigation latérale sur la même ligne et la même colonne. Ils se retrouvent ainsi les uns sur les autres dans une grille 1x1.
Grâce à cette fonctionnalité d'empilement responsif comme base, nous pouvons désormais exploiter l'état de la barre d'URL pour activer/désactiver la visibilité et le style de transition de la navigation latérale.
Mettez à jour l'élément <aside>
dans app/index.html
:
<aside>
<aside id="sidenav-open">
Cela permet au CSS de faire correspondre un élément et le hachage de l'URL. C'est important pour l'utilisation de :target
.
L'ID de l'élément peut désormais correspondre au hachage d'URL que nous allons définir avec les balises <a>
.
De plus, pour faciliter le ciblage JavaScript, ajoutez des ID pour les éléments clés qui contrôlent le sidenav. Tout d'abord, ajoutez un ID au lien d'ouverture de la navigation latérale :
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
Ajoutez ensuite un ID au lien de fermeture de la navigation latérale :
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
Nous avons terminé la mise en page d'empilement réactif de la macro <body>
et nous sommes maintenant liés à la barre d'URL.
Continuons.
La <aside>
est également bien agencée. Il comporte deux enfants : un <nav>
qui est le composant en forme de papier qui se déplie et un élément de lien de fermeture <a>
qui définit l'URL sur #
.
Le lien est invisible à droite du menu déroulant de la page. Il permet aux utilisateurs de "cliquer en dehors" du composant visuel pour le fermer.
Ajoutez le code CSS suivant à css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
J'ai trouvé que le ratio et les noms étaient une très bonne idée ici, où la grille pouvait briller et donner beaucoup de contrôle à un concepteur.
Ensuite, je dois superposer conditionnellement le contenu principal et conserver ma position lors du défilement du document. C'est un excellent travail pour position: sticky
et certains overscroll-behavior
.
Ajoutez les styles suivants pour la barre de navigation latérale :
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
Ces styles garantissent que la barre de navigation latérale correspond à la hauteur de la fenêtre d'affichage, qu'elle défile verticalement et qu'elle contient le défilement. Plus important encore, il masque l'élément. Par défaut, lorsque la fenêtre d'affichage est inférieure ou égale à 540px
, masquez la barre de navigation latérale. À moins que !
Ajoutez un pseudo-sélecteur :target
à l'élément #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
Lorsque l'ID de cet élément et la barre d'URL sont identiques, définissez visibility
sur visible
. Ouvrez le menu latéral après avoir fait défiler la page ou essayez de faire défiler la page pendant que le menu latéral est ouvert. Qu'en pensez-vous ?
Ajoutez le code CSS suivant en bas de app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
Ces styles ciblent nos boutons d'ouverture et de fermeture, spécifient leurs styles de pression et tactiles, et les masquent également lorsque les fenêtres d'affichage sont de 540px
ou plus.
Pour ajouter une touche d'originalité, ajoutons des transformations CSS tout en respectant l'accessibilité.
Ajoutez le code CSS suivant à css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
Ajouter du code JavaScript
La touche Escape
devrait fermer le menu. Ajoutez ce code JS à js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
Cela permet d'écouter un événement de touche sur l'élément sidenav.
Si la valeur est Escape
, le hachage de l'URL est défini sur une chaîne vide, ce qui fait disparaître le panneau latéral.
La gestion de la mise au point est la prochaine partie de l'UX JS. Je veux faciliter l'ouverture et la fermeture, alors j'attends que la navigation latérale ait terminé une transition quelconque, puis je la compare au hachage de l'URL pour déterminer si elle est ouverte ou fermée. J'utilise ensuite JavaScript pour définir le focus sur le bouton complémentaire à celui sur lequel l'utilisateur vient d'appuyer.
Ajoutez le code JavaScript suivant à js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
Essayer
- Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran
.
Conclusion
C'est tout pour les besoins que j'avais avec le composant. N'hésitez pas à vous en inspirer, à le piloter avec l'état JavaScript au lieu de l'URL, et à le personnaliser à votre guise ! Il y a toujours plus à ajouter ou plus de cas d'utilisation à couvrir.
Ouvrez css/brandnav.css
pour découvrir les styles non liés à la mise en page que j'ai appliqués à ce composant. Je ne pensais pas que c'était important pour l'ensemble des fonctionnalités sur lesquelles je me concentrais, et j'espérais que la séparation des styles et de la mise en page encouragerait le copier-coller. Vous pourriez y apprendre de nouvelles choses !
Comment créer des composants de barre de navigation latérale responsive et coulissante ? Avez-vous déjà eu plus d'un bouton, par exemple un de chaque côté ? J'aimerais présenter votre solution dans une vidéo YouTube. N'hésitez pas à me mentionner sur Twitter ou à commenter sur YouTube en indiquant votre code. Cela aidera tout le monde !