Aligner icônes et texte

Je n’arrive pas à croire que je viens seulement de m’attacher à ce problème suffisamment longtemps pour lui trouver une solution simple. Si vous ne l’avez pas fait autant vous en faire profiter.

Le problème

Une image adjacente à du texte n’apparaît pas verticalement centrée par rapport à ce dernier :

<svg style="height: 1em; width: 1em;" viewBox="0 0 24 24">  
    <path d="M0 0h24v24H0z" fill="none"/>
    <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92A3.4 3.4 0 0 0 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8a4 4 0 1 1 8 0c0 .88-.36 1.68-.93 2.25z"/>
</svg> WTF  

WTF

Verticalement centrée… Vous pensez à vertical-align: middle; n’est-ce pas ?

NOPE

Bon.

La valeur par défaut de vertical-align est baseline, qui aligne la ligne de base de la boîte avec celle de son parent. Ici nous avons deux boîtes : une générée par l’icône et une générée par le texte.

Leur ligne de base est bien alignée avec celle du parent, le problème c’est que leur ligne de base n’est pas au même endroit, et ceci car nous avons affaire à deux types de boîte : celle du texte est « inline » tandis que celle de l’icône est « inline-block ».

CSS assumes that every font has font metrics that specify a characteristic height above the baseline and a depth below it.

The baseline of an 'inline-block' is […], unless it has […] no in-flow line boxes […], in which case the baseline is the bottom margin edge.

Dans notre cas la ligne de base de la boîte contenant le texte est entre l’ascent et la descent définies par sa police, et celle de la boîte contenant l’icône est sa marge basse.

Le jeu va donc consister à savoir de combien modifier l’alignement vertical. Si nous baissons la boîte de l’icône jusqu’à obtenir un visuel satisfaisant, il s’agira de la distance entre les lignes de base des deux boîtes.

Ceci fait… plus rien n’a l’air d’être aligné ! Et pourtant…

L’icône est centrée verticalement par rapport à la hauteur des lettres majuscules ! On appelle cette hauteur « hauteur de capitale » (cap height en anglais).

La solution

Il va falloir baisser l’icône de la moitié de la différence entre sa hauteur et la hauteur de capitale. Nous pouvons obtenir cette dernière en em en la divisant par le cadratin de la police.

Au final, la formule suivante nous donne la valeur de vertical-align nécessaire :

  • I est la hauteur de l’icône en em
  • C est la hauteur de capitale de la police
  • E est le cadratin de la police

Ouvrons font-forge pour récupérer ces valeurs.

La police utilisée ici — Libre Franklin — a une hauteur de capitale de 742 et un cadratin de 1000. Par conséquent sa propriété vertical-align devra avoir pour valeur , soit −0,129em.

<svg style="height: 1em; vertical-align: -.129em; width: 1em;" viewBox="0 0 24 24">  
    <path d="M0 0h24v24H0z" fill="none"/>
    <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</svg> YAY  

YAY