Aligner icône et texte

Par défaut, une image adjacente à du texte ne s’aligne probablement pas comme souhaité.

<style>
    svg {
        height: 1em;
        width: 1em;
    }
</style>

<svg 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" fill="currentColor"/>
</svg> WTF
WTF

Ceci, car la valeur par défaut de la propriété vertical-align est baseline. C’est donc la ligne de base de l’icône et du texte qui sont alignées :

Pour être plaisant à l’œil, le centre vertical de l’icône doit être aligné avec la moitié de la hauteur visuelle du texte adjacent. Or, une seule valeur de vertical-align permet d’aligner le centre vertical de notre icône : middle.

Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

Notre icône est alors centrée par rapport à la hauteur d’x (x-height) du parent.

Si le texte n’est constitué que de minuscules, nous pouvons donc nous arrêter là ! Si non, il nous faut remonter l’icône pour la centrer par rapport à la hauteur de majuscule (cap height). De quelle distance ?

Comme notre icône est actuellement centrée par rapport à la x-height, il s’agira de la moitié de la différence entre cette dernière et la cap height. Par chance, CSS dispose respectivement des unités ex et cap ! Nous pouvons donc écrire

svg {
    margin-top: calc(.5ex - .5cap);
    vertical-align: middle;
}
WTF

Notez que si l’unité cap profite d’un support tout à fait honorable, il reste éventuellement moyen de s’en passer si vous devez supporter des navigateurs plus anciens : nous pouvons généraliser cap height en fonction de x-height car la lisibilité d’une fonte dépend entre autres de leur ratio. Les rares ressources que j’ai pu trouver à ce sujet permettent d’estimer une valeur nominale de 147%. Autrement dit, 1cap ≊ 1.47ex. Partant de cette approximation leur différence est égale à .47ex qui divisée par deux donne .235ex.

En tout cas chez moi ça marche.

svg {
    margin-top: -.235ex;
    vertical-align: middle;
}
WTF