Màj: 2009
display: inline-block?display: inline-block?
La propriété CSS display accepte de nombreuses valeurs, dont les plus connues sont inline (utilisée pour afficher un bloc comme un élément en ligne), block (utilisée pour afficher un élément en ligne comme un bloc) et none (efface l'élément de la page). On connait moins des valeurs telles que table-cell ou inline-block, pour une bonne raison: le support de ces valeurs par les navigateurs n'est pas très bon.
C'est dommage, car display: inline-block peut s'avérer très utile. Le principe: on affiche un élément (qu'il soit de type bloc ou de type en-ligne) comme une «boite en ligne»: c'est une boite, qui peut avoir des dimensions (hauteur, largeur), des marges et du padding aussi bien horizontalement que verticalement, etc., et en même temps c'est un élément comparable à un caractère de texte qui vient se poser sur la ligne de texte. Un élément en display: inline-block se placera sur la ligne de texte créé par son conteneur de la même manière qu'une image (élément img) ou tout autre élément remplacé (comme certains contrôles de formulaire par exemple).
Cela peut être très pratique pour le positionnement des éléments, surtout quand on bute sur les limites de la propriété CSS float. Par exemple: si on veut aligner des blocs, on pourra utiliser float: left. Mais si en plus on veut les centrer horizontalement dans leur conteneur, sans savoir à l'avance quelles seront les largeurs du conteneur, des blocs ou même le nombre de blocs, on aura besoin de display: inline-block.
Autre utilisation possible: le centrage vertical d'éléments. Un élément en display: inline-block peut recevoir un vertical-align: middle et ainsi être centré dans son conteneur. On pourra aussi utiliser vertical-align: bottom pour faire descendre l'élément en bas de son conteneur ayant une hauteur fixe ou une hauteur minimale. Plutôt pratique, non?
En ce qui concerne l'implémentation de display: inline-block, il y a les bons élèves, les élèves en difficulté, et les cancres notoires.
Les navigateurs Opera, Safari et Konqueror ont un support correct de ce type d'affichage (versions testées: Opera 9, Safari 2, Konqueror 3.5). Voilà, bravo à eux.
Internet Explorer pour Windows (depuis la version 5.5) a un support correct de ce type d'affichage… mais uniquement pour les éléments de type en-ligne tels que les éléments span par exemple. Un div {display: inline-block;} n'aura aucun effet dans Internet Explorer.
Le pire, c'est qu'il y mettrait presque de la mauvaise volonté, le bougre! Car si on place des éléments de type bloc dans un élément span en display: inline-block, on obtient le rendu souhaité! On pourrait donc envisager d'écrire ceci:
<span style="display: inline-block;">
<p>Un paragraphe</p>
<p>Un deuxième paragraphe</p>
<p>Et un dernier pour la route</p>
</span>
Mais cela pose deux problèmes:
Bref, cette astuce n'est pas vraiment utilisable.
Une bonne nouvelle tout de même: il y a de bonnes chances pour que le support de display: inline-block soit assuré dans Internet Explorer 8. Mauvaise nouvelle: non seulement ce navigateur ne doit pas sortir avant un certain temps à l'heure où j'écris (février 2008), mais en plus il lui faudra quelques années de plus pour devenir suffisamment répandu.
Pour une fois, le cancre c'est… Mozilla Firefox. Dans ses versions 1 et 2, Mozilla Firefox ignore totalement display: inline-block. La version 3, qui sortira courant 2008, corrige le tir (on peut déjà le constater avec les versions beta de Firefox 3). Il était temps!
Bonne nouvelle: les nouvelles versions de Firefox sont en général très rapide à s'imposer. Après sa sortie, il faudra sans doute à peu près un an à la version 3 pour représenter 90% des utilisateurs de Firefox.
Si si, il y en a! Et en les combinant, on arrive à une solution plutôt efficace. Voyons un peu le détail de ces astuces.
display: inline et de HasLayoutPour un élément de type bloc, nous ne pouvons pas utiliser display: inline-block avec Internet Explorer. Mais il existe un cas dans lequel un élément de type bloc aura le même type de comportement. Les conditions à remplir sont les suivantes:
display: inline;Disons que nous avons une suite d'éléments div ayant pour classe «inlineblock» (note: le nom de la classe est arbitraire, on peut choisir «choucroute» si on préfère). On pourra avoir le code CSS suivant:
div.inlineblock {
display: inline;
zoom: 1;
}
Comme cette astuce concerne uniquement Internet Explorer pour Windows, et uniquement les versions 5.5 à 7, on pourra adresser ce code CSS à Internet Explorer uniquement, via un commentaire conditionnel.
De plus, on pourra probablement se passer du zoom: 1, si on utilise une autre propriété (cette fois-ci adressée probablement à tous les navigateurs) qui confère le layout au bloc. Par exemple: une largeur fixe en pixels ou bien un… display: inline-block.
Nous verrons un code HTML et CSS complet utilisant ce correctif un peu plus loin.
-moz-inline-stackMozilla Firefox 1 et 2 ne comprend pas la valeur inline-block, mais il utilise en interne des valeurs propriétaires, précédées du préfixe -moz-. Il y a notamment:
-moz-inline-block-moz-inline-box-moz-inline-stackSauf erreur de ma part, -moz-inline-block ne donne aucun résultat quel qu'il soit (je me demande même si la documentation de Mozilla où elle est mentionnée n'est pas erronée). Ensuite, -moz-inline-box est plus intéressant, mais pose un gros problème: le contenu de chaque boite en display: -moz-inline-box passe sur une seule ligne et déborde allègrement. Inutilisable en dehors du centrage d'une série de vignettes (sans légende) par exemple.
Nous avons plus de chance avec -moz-inline-stack, dont le comportement se rapproche de ce que nous souhaitons. Je n'ai remarqué qu'un seul véritable problème: lorsque l'élément en display: -moz-inline-stack a plusieurs enfants, tous les enfants sont affichés superposés (les uns par dessus les autres). On évite ce problème en intercalant un élément div, de sorte que l'élément en display: -moz-inline-stack n'a qu'un seul élément enfant.
L'illustration suivante montre le problème rencontré et le rendu obtenu grâce au rajout d'un div «intercalaire»:

Il faudra donc, dans certains cas, alourdir un peu la structure HTML pour obtenir le bon rendu dans Firefox 1 et 2.
Mais comment allons-nous faire pour adresser ce correctif à Firefox 1 et 2, et pas aux autres navigateurs (y compris Firefox 3)? Nous n'avons pas de moyen ad hoc comme les commentaires conditionnels d'Internet Explorer. On procèdera donc ainsi:
div.inlineblock {
display: -moz-inline-stack;
display: inline-block;
}
Firefox 1 et 2 appliqueront la première déclaration, puis ignorerons la seconde qu'ils ne comprennent pas. Firefox 3 lira bien les deux déclarations, mais appliquera uniquement la seconde (la valeur qui vient en deuxième écrasant la première). Enfin, les autres navigateurs ignoreront la première déclaration qu'ils ne comprennent pas, et appliqueront la seconde.
Voilà, nous avons notre correctif, qui est compatible Firefox 1 et 2 et qui ne gênera pas les autres navigateurs.
display: inline-block uniquementNous partons du code HTML suivant afin de tester plusieurs cas de figure:
<p>
<span class="inlineblock">span 1</span>
<span class="inlineblock">span 2</span>
<span class="inlineblock">span 3</span>
</p>
<div class="inlineblock">div 1</div>
<div class="inlineblock">div 2</div>
<div class="inlineblock">div 3</div>
<div class="inlineblock bigbox">
<p>…</p>
<p>…</p>
</div>
<div class="inlineblock bigbox">
<p>…</p>
<p>…</p>
</div>
<div class="inlineblock bigbox">
<p>…</p>
<p>…</p>
<p>…</p>
</div>
Dans un premier temps, nous nous contentons du code CSS suivant:
div#test1 .inlineblock {
/* Indispensable */
display: inline-block;
/* Positionnement vertical du bloc */
vertical-align: middle;
/* Cosmétique */
margin: 10px;
border: solid 1px red;
padding: 40px;
background: #eee;
}
div#test1 .bigbox {
/* Important pour limiter la largeur des blocs en inline-block ayant un contenu long */
width: 150px;
}
Et voici le résultat que nous obtenons:
Exemple 1: utilisation de display: inline-block uniquement
Comme dit plus haut, l'utilisation de display: inline-block pose problème avec les navigateurs Internet Explorer pour Windows et Mozilla Firefox (avant la version 3). Mais on peut appliquer des correctifs pour obtenir un résultat très proche.
display: inline-block avec correctifsCommençons par le code HTML utilisé. C'est exactement le même que pour le premier exemple, avec une seule petite différence: lorsqu'un élément en display: inline-block a plusieurs enfants, on encadre ces enfants dans un conteneur unique (une simple div), afin d'éviter un problème de rendu avec le mode de rendu -moz-inline-stack dans Firefox 1 et 2. Le code HTML, donc:
<p>
<span class="inlineblock">span 1</span>
<span class="inlineblock">span 2</span>
<span class="inlineblock">span 3</span>
</p>
<div class="inlineblock">div 1</div>
<div class="inlineblock">div 2</div>
<div class="inlineblock">div 3</div>
<div class="inlineblock bigbox">
<div>
<p>…</p>
<p>…</p>
</div>
</div>
<div class="inlineblock bigbox">
<div>
<p>…</p>
<p>…</p>
</div>
</div>
<div class="inlineblock bigbox">
<div>
<p>…</p>
<p>…</p>
<p>…</p>
</div>
</div>
Passons maintenant au code CSS. Comme nous utilisons un commentaire conditionnel pour Internet Explorer, je vous présente le code CSS encadré dans des balises <style>…</style>. Bien entendu, la plupart de ce code CSS pourra être placé dans une feuille de styles externe (sans doute votre feuille de styles principale). Les correctifs pour IE 5.5-7 pourront être dans une feuille de styles externe également, mais cette feuille de styles devra être appelée via un commentaire conditionnel.
<style type="text/css" media="screen">
.inlineblock {
/* Indispensable */
display: -moz-inline-stack; /* Pour Firefox 1-2 */
display: inline-block; /* Écrase la valeur précédente si le navigateur comprend inline-block */
/* Positionnement vertical du bloc */
vertical-align: middle;
/* Cosmétique */
margin: 10px;
border: solid 1px red;
padding: 40px;
background: #eee;
}
.bigbox {
/* Important pour limiter la largeur des blocs en inline-block ayant un contenu long */
width: 150px;
}
</style>
<!--[if lte IE 7]>
<style type="text/css" media="screen">
.inlineblock {
/* Indispensable */
display: inline;
/* HasLayout -- peut faire doublon avec une autre propriété,
mais autant l'indiquer pour être sûr que le bloc aura le layout. */
zoom: 1;
}
</style>
<![endif]-->
Et voici le résultat:
Exemple 2: utilisation de display: inline-block avec correctifs
Voilà qui est déjà plus convaincant dans Firefox et Internet Explorer!
Une fois les deux correctifs mis en place, je n'ai pas rencontré de problème particulier. Si vous en rencontrez, vous pouvez me les signaler. Mise à jour: des problèmes à signaler avec -moz-inline-stack.
On peut imaginer que les solutions trouvées pour Internet Explorer (avant sa version 8) et Mozilla Firefox (avant sa version 3), qui «émulent» un affichage de type «inline-block», risquent de poser des problèmes dès que l'on voudra faire une utilisation très avancée de ce type d'affichage, pour une mise en page complexe. Mais globalement, pour des choses relativement simples, ces solutions me semblent correctes.
Enfin, c'est une chose difficile à affirmer sans des tests complémentaires et des tests en situation réelle, mais cette solution me semble utilisable en production.
En plus de mes tests personnels, je me suis inspiré des documents suivants: