Dompter la hauteur de ligne

Voir la vidéo

Une des choses qui me rend complètement fou lorsque je travaille sur du CSS, c'est la gestion de la hauteur de ligne par les navigateurs. Pour rappel, la hauteur de ligne représente l'espace que l'on a entre 2 lignes de texte. Mais dans le cadre du CSS, cette valeur affecte aussi la hauteur de l'élément qui accueille le texte, même si on n'a qu'une seule ligne de texte.

Le problème

À première vue, ce n'est pas forcément un problème important. Cependant, lorsqu'un élément accueille comme premier enfant du texte l'espace supplémentaire créé par la hauteur de ligne va générer un déséquilibre. Pour vous donner un exemple, voici une carte qui a une marge intérieure de 16 pixels. A gauche, le premier enfant est une image et à droite un titre.

Exemple de padding
Si on mesure l'espace visible à l'écran, on remarque que l'espace en haut du titre est supérieur à l'espace au dessus de l'image, malgré que la valeur de padding soit de 16 pixels pour les 2 éléments. Cet espace supplémentaire est créé à cause de la hauteur de ligne du titre.

On pourrait alors se dire que mettre une hauteur de ligne égale à la taille du texte devrait résoudre le problème. Cependant, même avec une hauteur de ligne de 1em, un espace reste visible au dessus de nos caractères. Et de toute façon, ce n'est pas une solution viable car nos titres peuvent être sur plusieurs lignes.

La cause

Pour comprendre la cause du problème, il est important de comprendre comment une police est dessinée. Lorsqu'une fonderie crée une police, elle commence par définir une unité importante : le UnitsPerEm (UPM). Cette valeur sans unité servira de référence lorsqu'il s'agira de dimensionner la police et servira aussi de base dans la création des différent glyphs.

Si par exemple, une police a un UPM de 1000, et que l'on souhaite avoir une taille de texte de 16px, une unité aura comme valeur 0.016px. Ensuite, plusieurs axes clés vont être utilisés pour faire en sorte que la police soit cohérente :

  • xHeight, sera la hauteur d'un X minuscule et servira de repère pour les caractères minuscule.
  • capHeight, sera la hauteur d'une majuscule
  • Ascent, représentera le point le plus haut de notre police
  • Descender, sera le point le plus bas (souvent négatif)

Metrics d'une police
Pour vous donner un exemple réel, voici les dimensions de la police Inter :

Metrics d'une police

Hauteur de majuscule et Units per Em

Le premier problème que l'on peut déjà observer est que la hauteur d'une majuscule ne correspond pas à Units per Em. Ce qui veut dire que lorsque l'on choisit une taille de police de 16 pixels, avec une hauteur de ligne de 16 pixels, nos caractères majuscules ne feront pas 16 pixels et il y aura nécessairement de l'espace blanc autour des caractères.

Positionnement par le navigateur

Maintenant que l'on a un peu petit peu mieux compris les dimensions utilisées lorsque l'on crée une police, on peut se pencher sur comment le rendu côté navigateurs fonctionne.

Dans un premier temps, le navigateur va charger la police et obtenir les différentes métriques. Il va utiliser la valeur du UnitsPerEm pour savoir comment dimensionner notre police.

Metrics d'une police
Une fois la dimension est obtenue, il faut placer la police correctement dans l'espace alloué (cet espace correspond à la hauteur de ligne). Et le navigateur a une logique simple, il va faire en sorte qu'il y ait le même espace qui dépasse (en utilisant le ascender / descender comme repère) en haut et en bas. En d'autres termes, il va centrer la police au milieu de notre espace en utilisant comme point de repère la hauteur maximale des caractères.

Metrics d'une police
Ce positionnement à plusieurs conséquences :

  • La baseline n'est pas une valeur fixée par le navigateur et varie d'une police à l'autre (l'espace autour des caractère varie suivant la police).
  • Si la police a un ascender important, la police aura tendance à être déplacée vers le bas.

Les solutions

Maintenant que l'on a bien compris les problèmes et leurs origines, il est important de voir s'il existe des solutions pour limiter l'impact qu'à le placement des textes sur les espacements.

CSS Text Box Trim

La première solution nous vient du CSS via une nouvelle propriété proposée au W3C : text-box-trim et text-box-edge

text-box-trim
Ces 2 nouvelles propriétés vont permettre de piloter comment le navigateur va découper les bords d'une police et permet ainsi de pouvoir retirer les espaces superflus au dessus de nos caractères.

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

C'est une solution idéale, mais qui a pour le moment comme gros inconvénient de n'être supporté par aucun navigateur. De plus, les spécifications continuent à évoluer et il n'y a pas de garantie que cette propriété devienne un standard (à titre d'information, elle a déjà changé plusieurs fois de nom et de valeur...).

Adapter les marges

La seconde solution, loin d'être idéale, est de changer les marges des éléments qui entourent le texte pour prendre en compte les espaces créés par la hauteur de ligne.

.card-with-text {
    padding: 7px 16px;
}

L'inconvénient de cette approche est qu'il est nécessaire de connaître à l'avance les enfants d'un élément pour pouvoir contrebalancer les espaces générés convenablement.

Marges négatives

La dernière solution, que je trouve être un bon compromis, est la mise en place de marges négatives autour de l'élément qui va accueillir le texte. Le problème est alors de calculer la valeur de marge en fonction de la police et de la hauteur de ligne utilisée. Heureusement pour nous, il existe des sites capables de faire ce calcul grâce au travail fait par Capsize qui répertorie l'ensemble des métriques associées aux différentes polices. Je me suis d'ailleurs créé un petit visualisateur pour obtenir les valeurs plus rapidement.

.font-inter {
  font-family: "Inter";
  line-height: 1.2
}

.font-inter::before {
  content: "";
  margin-bottom: -0.2362em;
  display: table;
}

.font-inter::after {
  content: "";
  margin-top: -0.2362em;
  display: table;
}

On notera que les marges négatives à appliquer dépendent de la hauteur de ligne et de la police mais pas de la taille de la police (vu que les marges sont définies en em). Dans l'exemple montré ci-dessus, on utilise des pseudo éléments afin de garder la possibilité d'avoir des marges qui affectent l'élément original. Il ne reste plus qu'à créer des classes qui correspondent aux différentes polices et hauteur de ligne que l'on a.

Publié
Technologies utilisées
Auteur :
Grafikart
Partager