La nouvelle méthode de positionnement en CSS
La nouvelle méthode de positionnement en CSS

La nouvelle méthode de positionnement en CSS

CSS a enfin eu son diplôme de géographie (et votre JS de positionnement est au chômage)

Catégories : CSS, Développement Web, Thérapie de groupe

Levez la main si vous avez déjà passé trois heures à écrire un script JavaScript juste pour qu'une maudite infobulle ne sorte pas de l'écran.

Oui, toi aussi. Ne mens pas.

Pendant des décennies, le positionnement en CSS c'était un peu comme donner des ordres à un stagiaire trop zélé et pas très malin.

Nous : "Mets-toi en bas à droite du bouton." CSS (en position: absolute) : "OK CHEF !" Nous : "Mais... tu sors de l'écran !" CSS : "J'AI FAIT CE QUE TU M'AS DIT. EN BAS À DROITE. JE SUIS EN BAS À DROITE. C'EST TON PROBLÈME MAINTENANT."

Résultat ? L'utilisateur devait composer avec la redoutée "barre de défilement horizontale de la honte" pour lire la fin d'un menu.

Pour corriger ça, on sortait l'artillerie lourde : JavaScript. On invoquait le mantra de l'enfer, getBoundingClientRect(), on calculait la largeur du viewport, on faisait des maths (DE TÊTE !) pour savoir s'il restait de la place, et on ajoutait une classe menu-va-a-gauche-s-il-te-plait.

C'était moche. C'était lourd. C'était fragile.

Eh bien, chers collègues traumatisés, j'ai une nouvelle. CSS a arrêté de sécher les cours. Il a enfin compris comment fonctionnait l'espace. Et il vient de mettre à la porte notre script position-helper.js.

Voici le plan en 3 étapes de CSS pour (enfin) gérer les pop-ups intelligemment.

Étape 1 : Le bouton ON/OFF natif (L'API Popover)

La première chose que faisait notre script JS, c'était de gérer l'affichage. display: none par-ci, display: block par-là. Sans oublier le document.addEventListener('click', ...) pour fermer le menu si on cliquait à côté.

C'est fini.

HTML (oui, HTML !) s'en charge.

Exemple de popoverindex.html
HTML
<!-- The button that turns on the TV -->
<button popovertarget="my-magic-menu">Open menu</button>

<!-- The TV -->
<div id="my-magic-menu" popover>
  I'm a menu!
</div>

C'est tout.

Avec juste popover et popovertarget, le navigateur gère NATIVEMENT :

Votre toggleMenu.js peut partir à la retraite.

Étape 2 : La laisse (Anchor Positioning)

Bon, c'est bien beau, notre menu s'affiche. Mais il s'affiche au milieu de nulle part. On veut qu'il soit attaché à son bouton, comme un petit chien.

Avant, on devait imbriquer le menu dans le bouton (beurk) ou utiliser position: relative sur un parent.

Maintenant, on leur met une laisse invisible.

1. On met un collier au bouton (l'ancre) :

Exemple Anchor buttonstyle.css
CSS
.my-button {
  /* "Your name is 'anchor-button' now" */
  anchor-name: --anchor-button;
}

2. On attache le menu (le popover) à la laisse :

Attachez le menu (la fenêtre contextuelle) à la laissestyle.css
CSS
.my-menu {
  position: absolute; /* That part doesn't change */

  /* "Your reference is 'anchor-button'!" */
  position-anchor: --anchor-button;

  /* * Stick your TOP EDGE (top) 
   * on the BOTTOM EDGE (bottom) of the anchor!
   */
  top: anchor(bottom);
  left: anchor(left);
}

Avec anchor(), on peut lier n'importe quel bord de notre menu à n'importe quel bord de notre ancre. C'est propre, c'est déclaratif, et ça marche même s'ils ne sont pas parents dans le DOM.

Étape 3 : Le Plan B (Position Fallbacks)

C'est là que CSS se met à frimer.

Notre menu est bien attaché. Mais on a toujours le même problème : si le bouton est tout à droite, notre menu va... oui, sortir de l'écran. CSS est toujours un peu bête.

... Sauf que maintenant, il a un cerveau.

On va lui donner des &quot;scénarios&quot; de positionnement avec une nouvelle règle : @position-try.

Exemple Position Trystyle.css
CSS
/* Scenario A (default):
   Try to open at the bottom right */
@position-try --bottom-right {
  top: anchor(bottom);
  left: anchor(left);
}

/* Scenario B (the fallback plan):
   If that doesn't work, try bottom left */
@position-try --bottom-left {
  top: anchor(bottom);
  right: anchor(right); /* <- The magic is here */
}

On a défini deux plans. Maintenant, on dit au menu de les essayer dans l'ordre :

Essayez-les dans l'ordrestyle.css
CSS
.my-menu {
  /* ... all the stuff from before ... */

  /* * "First try 'bottom-right'.
   * If it doesn't fit the screen, 
   * try 'bottom-left'."
   */
  position-try-fallbacks: --bottom-right, --bottom-left;
}

C'est fini. Je suis sérieux. Il n'y a pas d'autre étape.

Le navigateur va maintenant faire TOUT SEUL :

On peut même ajouter un plan C (--en-haut-a-gauche) et D (--en-haut-a-droite) pour gérer les cas où le bouton est tout en bas de la page.

JavaScript peut enfin prendre des vacances

Pendant que CSS gère enfin la géographie de base, que va faire notre pauvre script JS de 200 lignes ? Il peut aller se reconvertir. Faire des confettis à l'écran, gérer des animations complexes... des trucs amusants.

La gestion du positionnement, c'est désormais l'affaire du stagiaire qui a (enfin) validé son année.

La seule petite douche froide : Comme toute bonne chose, c'est flambant neuf. Au moment où j'écris ces lignes, ce n'est pas encore dispo dans tous les navigateurs. Mais c'est en train d'arriver à vitesse grand V (merci Chrome, Firefox et Safari pour le travail en cours !).

Préparez-vous : l'époque des getBoundingClientRect() est bientôt terminée. Et franchement, elle ne manquera à personne.