CSS: Astuce pour vertical-align: middle

L’alignement vertical en CSS est un enfer pour beaucoup de développeurs web.

Prenons text-align: center. C’est une propriété CSS qui centre horizontalement les enfants de l’élément portant la propriété (le conteneur) dans son flux : tous les enfants inline ou inline-block du conteneur seront donc centrés dans celui-ci.

Cependant, vertical-align ne fonctionne pas sur les enfants de l’élément portant la propriété. Il agit sur les éléments autour de celui-ci !

C’est un fonctionnement totalement contre-intuitif si on le compare à text-align: center et si on imagine que ce sont deux propriétés similaires dont le but est de centrer soit verticalement soit horizontalement des éléments dans un conteneur.

Cette confusion dans son fonctionnement apporte à vertical-align une mauvaise réputation et beaucoup de développeurs en herbe se cassent la tête quant à comment centrer verticalement un élément dans un autre.

Il existe pourtant une astuce relativement simple qui permet d’obtenir à coup sur l’alignement voulu.

Prenons l’exemple suivant :

Mon span
example



.wrapper {
height: 100px;
border: 1px solid #00f;
}
span,
img {
border: 1px solid #000;
vertical-align: middle;
}

Le but est de centrer les éléments (span et img) verticalement au milieu du div parent (.wrapper).

Avec le code ci-dessus, le résultat est le suivant :

Pas vraiment ce qu’on cherche à faire…

Que se passe-t-il ?

Chaque élément est aligné verticalement avec ses voisins, mais le tout n’est pas centré au milieu du div !

Que nenni, on ajout un vertical-align: middle; au parent ? Ca ne fait rien ! Comment ça ça ne fait rien ?!

Comme dit au dessus, vertical-align aligne (ici verticalement) les éléments les uns par rapport aux autres dans leur flux. Donc relativement à leurs frères et sœurs, pas relativement à leur parent ! On voit bien ici que le span et l’image sont bien centrés verticalement ensemble, mais qu’ils restent en haut du wrapper.

Vis à vis du parent, ce qui définit donc la position des éléments est donc le plus grand d’entre eux (ici l’image) qui va toucher le haut du div.wrapper.

Mais qu’est-ce qu’on cherchait à faire au fait ?! Aligner verticalement les éléments au milieu du div.

L’astuce : le bloc élongateur

L’astuce consiste donc à rajouter un élément vide dans le flux (au début, à la fin, qu’importe).

Cet élément ferait 100% de la hauteur du parent (et serait inline-block pour forcer sa hauteur). Il étirerait ainsi le flux inline jusqu’à ce qu’il fasse 100% de la hauteur du div.

Chaque élément se positionnant centré verticalement par rapport au plus grand dans le flux, on obtient ainsi l’effet voulu :

Mon span
example

Avec ceci en plus :

.valign {
height: 100%;
display: inline-block;
*display: inline; zoom: 1; /* inline-block pour IE6 */
border: 1px solid #f00;
}

Ce qui fait :

Vous allez me dire : « Le span, pourquoi on le fait pas faire 100% de la hauteur dans ce cas au lieu de rajouter un élément en plus dans le HTML ? »

Eh bien simplement parce que le texte, lui, est positionné en haut du span :

span {
height: 100%;
display: inline-block;
*display: inline; zoom: 1; /* inline-block pour IE6 */
border: 1px solid #f00;
}

Alternative avec line-height

Il existe une autre façon d’aligner verticalement, pour sa part bien connue, qui apporte un avantage assez sympa comparé à l’astuce précédente, et qui est à base de line-height.

Il s’agit simplement de donner un line-height à un des éléments du flux et de le fixer à 100% de la taille en hauteur du parent (ce qui a pour effet de définir la taille du flux).

Seulement, problème : on ne peut pas fixer de line-height à « 100% » : Seulement à une valeur fixe, en pixels. On doit donc connaître la taille exacte en pixels du parent pour donner au line-height la même valeur.


span,
img {
border: 1px solid #000;
vertical-align: middle;
line-height: 100px;
}

Cette astuce a donc comme avantage d’éviter d’introduire un bloc supplémentaire dans le HTML (le span.valign) mais a aussi comme inconvénient de devoir connaitre la hauteur du parent (et en pixels, ce qui n’est pas toujours une information connue ou connaissable !).

Et vous ? Avez-vous d’autres astuces intéressantes pour centrer des éléments verticalement dans un élément sans avoir recours à du Javascript ?

PS : L’image à la une a été prise par Exey Panteleev.

Commentaires