The CSS vertical-align Problem Is Finally Solved: text-box-trim and margin-block

The CSS vertical-align Problem Is Finally Solved: text-box-trim and margin-block

lschvn7 min de lecture

Ouvrez un bouton dans l'inspecteur de votre navigateur. Ajoutez du padding. Le texte semble centré. Ajoutez davantage de padding, ou changez de police. Soudain, il est décalé de 4 pixels. Ce n'est pas un bug dans votre CSS. C'est une inadéquation fondamentale entre la manière dont les navigateurs mesurent le texte et celle dont les êtres humains le perçoivent.

Le problème — L'interlignage

Pour comprendre pourquoi le texte ne scentre jamais tout à fait, il faut comprendre ce que les navigateurs mesurent réellement. Chaque police possède un ensemble de métriques : la hauteur des capitales (la hauteur des lettres majuscules), la ligne de base (sur laquelle reposent les lettres), l'ascendante (distance entre la ligne de base et le sommet des lettres hautes) et la descendante (distance sous la ligne de base). Ces métriques définissent le carré em, la zone invisible qui contient chaque glyphe.

Mais il y a un piège. Lorsque vous définissez line-height: 1.5 sur un texte de 16px, le navigateur alloue 24px d'espace vertical. Le texte visuel réel — les lettres elles-mêmes — n'occupent qu'environ 11px dans le centre vertical de cette zone de 24px. L'espace restant s'appelle l'interlignage : un padding invisible distribué au-dessus de la hauteur des capitales et sous la ligne de base.

Les navigateurs alignent le texte sur cette zone de line-height, et non sur les lettres visuelles. Voilà pourquoi le texte d'un bouton semble toujours se trouver dans la moitié inférieure de son conteneur, même avec display: flex; align-items: center. La zone de line-height s'étend plus haut au-dessus de la hauteur des capitales qu'elle ne descend sous la ligne de base, de sorte que le centre visuel des lettres se situe bien en dessous du centre géométrique de l'espace alloué.

Cette inadéquation affecte chaque conteneur de texte étroit : boutons, badges, éléments de navigation, champs de saisie. Vous pouvez ajouter tout le padding souhaité — tant que vous n'adressez pas l'interlignage, le texte ne sera jamais vraiment centré.

Solution 1 — text-box-trim

La spécification CSS Text Level 4 introduit text-box-trim, une propriété qui permet de supprimer directement l'interlignage du texte en ligne. La propriété accepte trois valeurs : trim-start supprime l'espace au-dessus du texte, trim-end supprime l'espace en dessous, et trim-both supprime les deux.

Pour contrôler précisément quelle partie de la métrique de la police est rogée, associez-la avec text-box-edge. Cette propriété accepte des valeurs comme cap, alphabetic, ex et text — chacune représentant une mesure différente dans le carré em de la police.

Pour l'ajustement vertical le plus étroit, utilisez text-box-edge: cap alphabetic combiné avec text-box-trim: trim-both. Cela indique au navigateur de rogner depuis la hauteur des capitales jusqu'à la ligne de base alphabétique, supprimant tout l'interlignage au-dessus et en dessous des lettres visibles.

.button-text {
  text-box-edge: cap alphabetic;
  text-box-trim: trim-both;
}

La compatibilité avec les navigateurs est actuellement limitée aux versions les plus récentes. Cela fait de text-box-trim une amélioration progressive idéale : vous l'appliquez pour les navigateurs qui la supportent tout en maintenant un fallback pour les autres.

Solution 2 — margin-block

Si vous avez besoin de code fonctionnel aujourd'hui, margin-block avec des unités relatives à la police délivre le même résultat avec une excellente compatibilité navigateurs. La technique utilise deux unités CSS moins connues : cap, qui équivaut à la hauteur des capitales de la police actuelle, et lh, qui équivaut à la valeur calculée de line-height.

La formule est élégante :

.button-text {
  margin-block: calc(0.5cap - 0.5lh);
}

Cela produit une marge négative qui compense la zone de line-height par rapport à la hauteur des capitales. La moitié de la hauteur des capitales moins la moitié du line-height donne exactement la distance nécessaire pour tirer le texte visuel vers le centre de son espace alloué. Comme cap et lh s'échelonnent tous deux avec la police, cela fonctionne correctement quelle que soit la taille ou la famille de police.

Pour une police de 16px avec line-height: 1.5 (24px), le calcul produit environ -4px. Cette marge négative soulève le texte visuel vers le centre géométrique. Le résultat est le même ajustement précis et serré que celui fourni par text-box-trim — mais disponible dans chaque navigateur moderne dès aujourd'hui.

Motif d'amélioration progressive

L'approche judicieuse combine les deux techniques : commencez par margin-block comme base, puis enrichissez avec text-box-trim là où c'est supporté. La clé consiste à utiliser @supports pour détecter le support de text-box-trim et annuler le margin-block à l'intérieur de ce bloc.

.button-text {
  /* Base : fonctionne partout */
  margin-block: calc(0.5cap - 0.5lh);
}

/* Amélioration : utiliser text-box-trim lorsqu'il est disponible */
@supports (text-box-trim: trim-both) {
  .button-text {
    text-box-edge: cap alphabetic;
    text-box-trim: trim-both;
    margin-block: 0;
  }
}

Ce motif garantit que chaque navigateur obtient un alignement textuel correct. Les navigateurs plus anciens obtiennent la solution margin-block. Les navigateurs à la pointe obtiennent l'approche native text-box-trim. Aucun navigateur n'obtient un double ajustement ni une mise en page cassée.

Cas d'utilisation réels

Texte de bouton : Appliquez margin-block: calc(0.5cap - 0.5lh) à l'élément texte du bouton tandis que le bouton lui-même utilise display: inline-flex; align-items: center. Cela vous donne un texte de bouton parfaitement centré qui tient lorsque vous changez de police ou ajustez le padding.

Badges et pilules : Les conteneurs à padding serré révèlent l'inadéquation instantanément. Ajoutez margin-block au texte du badge et regardez l'étiquette s'aligner au centre géométrique, même avec un padding asymétrique.

Titres hero : Le texte d'affichage de grande taille rend même de minuscules inadéquations évidentes. margin-block sur un titre de 72px avec line-height: 1.1 délivre l'alignement au pixel près que les designs premium exigent.

Icône + texte : Lors de l'appairage d'une icône avec du texte en utilisant display: flex; align-items: center, ajouter margin-block à l'élément texte garantit que l'icône et les lettres partagent la même ligne de base visuelle, même lorsque leurs métriques internes diffèrent.

Le texte a toujours été légèrement décalé au centre en CSS — non pas à cause de bugs, mais à cause de la manière dont les navigateurs mesurent l'espace. Avec margin-block disponible aujourd'hui et text-box-trim arrivant bientôt, cette époque est finalement révolue.

Questions fréquentes

Articles connexes

Plus de couverture avec des sujets et tags en commun.

Pretext : La bibliothèque de mesure de texte sans DOM que les agents de codage IA utilisent déjà
layout

Pretext : La bibliothèque de mesure de texte sans DOM que les agents de codage IA utilisent déjà

Cheng Lou vient de publier Pretext, une bibliothèque JavaScript pure qui mesure et dispose du texte multiligne sans toucher au DOM. Voici pourquoi c'est important pour la virtualisation, le contrôle de layout et les agents IA qui génèrent du code UI.
Vue 3.5 : La version 'mineure' qui a réécrit les règles de la performance frontend
frontend

Vue 3.5 : La version 'mineure' qui a réécrit les règles de la performance frontend

Vue 3.5 est arrivé sans changements cassants et avec un ensemble d'amélioration des internals qui devrait attirer l'attention de tout développeur — 56% d'usage mémoire en moins, hydration paresseuse, et une API props réactive stabilisée.

Commentaires

Connexion Connectez-vous pour participer à la conversation.

Pas encore de commentaires. Soyez le premier à partager vos pensées.