J’aimerais pouvoir dire que la simplicité du menu de MacGeneration représente notre approche du journalisme technologique, et que l’absence totale de navigation sur le Club iGen est un triomphe de minimalisme. En vérité, je n’ai jamais été foutu de construire un menu de navigation vaguement présentable. Notre incapacité à embrasser la complexité de notre système d’information et organiser la taxonomie de nos contenus n’aide certainement pas, mais elle n’explique pas mes difficultés à concevoir le menu d’un « simple » blog.
Je crois que cela tient à mon approche architectonique de la structure d’une page web, en partant depuis l’enpied, comme une lourde fondation sur laquelle repose le reste de l’édifice. Le temps d’arriver au toit, je suis impatient d’en finir, alors je jette mes dernières forces avec deux coups de truelle. Sauf que ce qui pourrait passer inaperçu depuis le pied d’un immeuble de quarante étages est immanquable dans les quarante premiers pixels d’un écran tenu à dix centimètres du nez.
Alors cette fois, je commence par l’entête, que je conçois comme une charpente, pour filer la métaphore. On n’a jamais bâti une charpente avec trois cure-dents, mais on a fabriqué quelques cathédrales avec des forêts impénétrables. Qu’il prenne toute la hauteur des écrans verticaux, ou toute la largeur des écrans horizontaux, le menu de navigation doit déborder de liens, comme autant de poutres et de poteaux. La structure de l’entête est fort traditionnelle :
<div class="site-header">
<div class="content">
<h1 class="title">…</h1>
<input data-menu hidden id="menu-opener" type="checkbox" />
<label aria-controls="menu" aria-haspopup="true" aria-label="Ouvrir le menu" class="menu-button" for="menu-opener" id="menu-label" role="button">☰</label>
</div>
<div class="menu">…</div>
</div>
Le menu de navigation s’ouvre comme un tiroir, une interaction qui ne demande pas la moindre ligne de JavaScript, mais peut être entièrement réalisée avec des animations CSS. L’entête est ancré en bas de la fenêtre, une position atypique que je veux réutiliser depuis l’abandon des premières maquettes du Club iGen. Le menu est lui-même attaché à l’entête, mais d’abord caché sous le tapis avec la transformation transform: translateY(125%)
1 :
.site-header .content {
background: purple;
display: flex;
align-items: center;
justify-content: space-between;
height: 4em;
padding: 1em 1em 1em 1em;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 3;
}
.site-header .menu .navigation {
position: fixed;
bottom: 4em;
left: 0;
right: 0;
transform: translateY(125%);
z-index: 2;
}
Le sélecteur :has()
simplifie considérablement la rédaction de la mécanique d’ouverture, déclenchée en cochant la case qui porte l’attribut data-menu
. Le menu est alors révélé à l’aide de la transformation transform: translateY(0);
:
.site-header:has([data-menu]:checked) .menu .navigation {
transform: translateY(0);
transition: transform 0.5s cubic-bezier(0.5, 0.0, 0.25, 1);
}
Ces trois lignes de code sont plus importantes qu’il n’y parait : avant l’apparition du sélecteur :has()
, il n’était pas possible de changer l’apparence d’un enfant (.menu .navigation
) en fonction du comportement de son parent (.site-header
). Le sélecteur de voisin général ~
permet d’appliquer un flou sur le contenu principal (l’un des voisins de l’entête au sein du <body>
) lorsque la case est cochée dans l’entête (:has([data-menu]:checked)
) :
.site-header:has([data-menu]:checked) ~ .site-main {
filter: blur(5px);
transition: filter 0.5s cubic-bezier(0.5, 0.0, 0.25, 1);
}
Cette déclaration parsemée de caractères cryptiques devrait suffire à convaincre les développeurs les plus paresseux qu’ils devraient vraiment étudier les dernières évolutions de mon langage de programmation favori. Ou, disons, apprendre à centrer un élément sur les deux axes sans importer un framework de quelques dizaines de milliers de lignes de code. This Ain’t Your Father’s CSS.
L’entête et le menu sur un petit écran vertical.
Seuls les navigateurs les plus récents prennent en charge le sélecteur :has()
, et je n’ai pas prévu de « dégradation gracieuse » pour le moment, ce genre de raffinements viendra dans un second temps. La même logique de contrôle d’un enfant en fonction de l’état de son parent me permet d’ajouter un élément translucide qui assombrit légèrement l’arrière-plan :
.site-header:has([data-menu]:checked) .menu .overlay {
background: hsla(285, 10%, 5%, 75%);
position: fixed;
bottom: 0;
left: 0;
right: 0;
top: 0;
z-index: 1;
}
Sur les écrans horizontaux, l’entête passe à la verticale, une disposition qui constitue maintenant une signature personnelle. Le menu s’ouvre vers la droite, une disposition qui me donne l’occasion d’utiliser l’une de mes astuces favorites, l’utilisation d’une paire de boutons de fermeture :
<div class="menu">
<label class="overlay" for="menu-opener"></label>
<div class="navigation">
<label class="close" for="menu-opener">Fermer</label>
<div class="sections">…</div>
</div>
</div>
Le premier bouton, visible, offre l’affordance familière d’un simple lien de fermeture. Le deuxième bouton, invisible, n’est autre que cet élément translucide qui assombrit légèrement l’arrière-plan. En croyant cliquer en dehors du menu, l’utilisateur clique en fait sur un immense bouton de fermeture. La mécanique est dissimulée, mais l’interaction est naturelle.
L’arrière-plan reste interactif lorsque le menu est ouvert, et peut encore défiler alors même qu’il est assombri et estompé. Je doute que la propriété overscroll-behavior
suffise à résoudre le problème, et je devrai probablement écrire quelques lignes de JavaScript. La question du comportement réglée, je peux maintenant me concentrer sur le contenu. L’arrangement horizontal offre un petit aperçu de mes ambitions.
Cela suffirait…
…mais j’ai toujours été gourmand.
Une valeur de 100 % devrait suffire, mais l’effet de « rebondissement » à la fin du défilement dans Safari permet de voir quelques dizaines de pixels au-delà de la page web… et donc la poussière sous le tapis. Une valeur de 125 % est suffisante pour mettre le menu hors de portée, une valeur supérieure augmenterait la durée de l’« ouverture » du tiroir en lui faisant parcourir une plus grande distance. ↩︎