Centrer une image verticalement et horizontalement en CSS

Oh bordel, en voilà une question qui est posée sur StackOverflow et autres forums d'entraide depuis la nuit des temps du web !

Comment centrer une image dans une div ?
Bon, pour la centrer horizontalement rien de compliquer. Mais verticalement c'est une autre histoire !
Si vous faites une recherche Google (en Français ou en Anglais) sur le sujet, vous trouverez des tonnes de façon différentes de le faire. Je suis récemment tombé sur celle-ci, qui me semble réellement être la plus propre, la plus compatible avec les vieux navigateurs (jusqu'à IE7 (!!!) voir moins, je n'ai rien pour tester sous IE6) mais aussi les modernes et la plus efficace.

Comment on fait alors ?

Deux solutions s'offrent à vous, une avec du markup en plus (un span à ajouter), une sans.

Solution avec balise span

Tout simple au niveau du html, on rajoute une balise span avant l'image.

	<div class="container">
    	<span class="helper"></span>
        <img src="https://placekitten.com/g/140/120" />
	</div>

Quant au CSS :

.container {
    height: 280px;   
    width: 260px;
    text-align: center;
    
    border: 1px solid red; /* Afin de bien voir que c'est centré dans la boîboîte */
}

.container .helper {
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

.container img {
    vertical-align: middle;
}

La résultat :

Easy.

Solution avec :before

Ajouter une balise vide à notre markup, c'est pas génial.
On peut donc se servir du pseudo-selecteur :before pour éviter cet ajout superflu !

Le code HTML est pareil, mais sans balise span.

	<div class="container">
        <img src="https://placekitten.com/g/140/120" />
	</div>

Quant au CSS, ce qui était appliqué au helper est désormais appliqué au pseudo-selecteur.

.container {
    height: 280px;   
    width: 260px;
    text-align: center;
    
    border: 1px solid red; /* Afin de bien voir que c'est centré dans la boîboîte */
}

.container:before {
	content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

.container img {
    vertical-align: middle;
}

Est-ce que ça fonctionne ?

Yeah !

Mais attends, :before ça marche pas pour IE7 !

En effet, les pseudos-selecteurs n'ont été implémentés qu'à partir d'IE8 (et encore, de façon ératique). Il est cependant possible de contourner le problème de façon plutôt dégueulasse en utilisant les expressions css. Qu'est ce que c'est ? En gros une façon assez dégueu d'exécuter du JS dans un fichier CSS.

Si vous avez donc besoin d'une compatibilité <IE7 je vous invite à ajouter ce bout de CSS entre des commentaires conditionnels pour IE7 et moins uniquement.

.container_before {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

.container {
    list-style:none;
    behavior: expression(
        function(t){
            t.insertAdjacentHTML('afterBegin','');
            t.runtimeStyle.behavior = 'none';
        }(this)
    );
}

Comment ça marche ?

En fait le fonctionnement est étonamment assez simple. Je vous refait ici l'explication que donne le bonhomme qui a posté la solution sur Stack Overflow.

  1. Quand vous avez deux éléments inline-block l'un à côté de l'autre, vous pouvez aligner verticalement leur côtés respectifs, donc avec un vertical-align: middle vous aurez quelque chose de ce genre :

  2. Quand vous avez un block avec une hauteur fixe (en px, em ou tout autre unitée absolue), vous pouvez définir la hauteur des blocks internes en %.
  3. Donc ajouter un inline-block avec une hauteur à 100% dans un block avec une hauteur fixe permettra d'aligner verticalement tout autre inline-block à côté de lui.

Pas bien compliqué, mais il fallait y penser.


css | html


Strasbourg, France

Ingénieur en informatique chez Sully Group.