Note : Cet article est publié conjointement sur OpenWeb.eu.org et sur Alsacreations.com. En outre, certaines parties de cet article sont extraites du livre «CSS avancées, vers HTML5 et CSS3», avec l’aimable autorisation de l’auteur :)
Compatibilité
Commençons par une excellente nouvelle : le modèle de rendu tabulaire en CSS est finalisé depuis suffisamment longtemps pour être compatible avec tous les navigateurs actuels et leurs générations précédentes.
Il faut remonter aux antiques versions d’Internet Explorer 7 et précédentes pour trouver des navigateurs qui ne supportent pas ce schéma de positionnement.

Display
Depuis les spécifications CSS2, pas moins de 10 valeurs dédiées aux rendus tabulaires ont été ajoutées à la propriété display.
Vous connaissiez sans nul doute déjà les valeurs block, inline, none et inline-block, en voici de nouvelles dans notre arsenal à présent bien complet :
table- Spécifie un comportement de table de type bloc pour un élément.
C’est le rendu par défaut des éléments
<table> inline-table- Spécifie un comportement de table de type en-ligne pour un élément.
table-row- Spécifie que l'élément s’affiche comme une rangée de cellules.
C’est le rendu par défaut des éléments
<tr> table-row-group- Spécifie qu'un élément regroupe une ou plusieurs rangées.
C’est le rendu par défaut des éléments
<tbody> table-header-group- S’affiche comme
table-row-group, mais ce groupe de rangées est toujours affiché avant toutes les autres rangées et groupes de rangées. C’est le rendu par défaut des éléments<thead> table-footer-group- S’affiche comme
table-row-group, mais ce groupe de rangées est toujours affiché après toutes les autres rangées et groupes de rangées. C’est le rendu par défaut des éléments<tfoot> table-column- Spécifie qu'un élément représente une colonne de cellules.
C’est le rendu par défaut des éléments
<col> table-column-group- Spécifie qu'un élément regroupe une ou plusieurs colonnes.
C’est le rendu par défaut des éléments
<colgroup> table-cell- Spécifie qu'un élément doit s’afficher tel une cellule de table.
C’est le rendu par défaut des éléments
<th>et<td> table-caption- Spécifie le rendu d’une légende d'une table.
C’est le rendu par défaut des éléments
<caption>
En action !
Passons immédiatement à la pratique, et procédons à quelques tests de routine.
Prenons au hasard deux éléments «block» classiques, disons deux <div>, et modifions simplement la valeur de leur propriété intrinsèque display (block) par la valeur «table-cell» :
div {display: table-cell;}
Avant (block) :

Après (table-cell) :

Les deux éléments s’affichent à présent l’un à côté de l’autre tels des éléments inline. Mais contrairement à un rendu inline, ces éléments table-cell peuvent être dimensionnés :
div {display: table-cell;}
div:first-child {width: 150px;}

Nous n’avons pas modifié la sémantique des éléments HTML, ce sont toujours des <div>, nous n’avons fait que modifier leur rendu par défaut via CSS, comme nous l’aurions fait en passant de display: block à display: inline par exemple.
Algorithme de calcul des tableaux
Contrairement à la croyance commune, ce n'est pas un mais un double algorithme qui définit le rendu des structures tabulaires :
- Le modèle automatique (
table-layout: auto) appliqué par défaut confère le pouvoir aux contenus des cellules. Ces derniers déterminent la largeur des colonnes : plus le contenu est dense, plus la colonne est large. Les largeurswidthrenseignées pour la table ou ses cellules ne seront qu’indicatives. - Le modèle fixe (
table-layout: fixed) se base sur la largeur réelle du tableau et de ses colonnes, et ne dépend pas du contenu.
Définir l’algorithme d’affichage en mode fixe a plusieurs avantages :
- Dès qu’un élément de colonne a une valeur
width, alors cette valeur est retenue pour la largeur de toute la colonne. Les éventuelles colonnes restantes se partagent équitablement l’espace horizontal restant de la table. - Le navigateur peut commencer à afficher la table dès la réception de la première rangée. De manière générale, cet algorithme accélère les traitements et l’affichage par le navigateur (pas de reflow inutile).
- Les contenus n’affectent pas les largeurs des colonnes. Toute cellule s’appuie sur la propriété
overflowpour déterminer le rognage, ou non, du contenu qui déborderait, ou encore des propriétés de césure telles queword-wrapouhyphens. - Dans le cas de tableaux de données complexes, mon expérience m’a appris à apprivoiser ce mode de rendu plus strict et robuste que le rendu automatique… et qui est reconnu dès Internet Explorer 5 (et les autres navigateurs également, bien entendu).
Prenons pour exemple : un parent tabulaire contenant trois enfants en table-cell. Les dimensions (width) de chaque élément sont spécifiés en CSS : 600px pour le parent et 200px pour chacun des trois enfants :

En ajoutant une image de plus de 200 pixels de large au sein de la première cellule, celle-ci s'étire ainsi que tout l'ensemble du tableau. Le contenu est roi, c'est le comportement par défaut de table-layout: auto :

En faisant bénéficier le parent d'un table-layout: fixed, chaque élément conserve ses largeurs définies, et le contenu déborde comme dans n'importe quel autre élément HTML :

Autres propriétés spécifiques aux tableaux
À l’instar de table-layout, certaines autres propriétés CSS sont spécifiques aux éléments de tableaux. Il s’agit de border-collapse, border-spacing, empty-cells et caption-side.
border-collapse- Comme c’est le cas pour les tableaux HTML, la propriété
border-collapsedétermine si les bordures de la table et entre les cellules doivent être séparées (valeurseparate) ou fusionnées (valeurcollapse). border-spacing- La propriété CSS
border-spacing, reconnue à partir d’Internet Explorer 8 (et équivalente à l’attribut HTMLcellspacingdevenu obsolète), spécifie la distance qui sépare les bordures de cellules adjacentes. - Lorsque deux valeurs sont renseignées, la première désigne l’espacement horizontal et la deuxième le vertical. La valeur de cette propriété devient automatiquement nulle lorsque
border-collapsea pour valeurcollapse. empty-cells- La propriété
empty-cells(à ne pas confondre avec le sélecteur CSS3:empty) gère l’affichage des cellules vides : la valeurhidemasque les bordures de la cellule. - Lorsque cette propriété est appliquée au sein d’une table ne comportant qu’une seule rangée, les cellules vides disparaissent complètement et les autres cellules se réorganisent sans elles. Cette propriété est prise en compte à partir d’Internet Explorer 8 et chez les autres navigateurs, bien entendu.
caption-side- Cette propriété, reconnue elle aussi depuis IE8, indique la position de la boîte de la légende en fonction de celle de la table. Les valeurs acceptées sont
top(par défaut) etbottom, mais aussileftetright, même si ces dernières ne sont actuellement comprises que par Firefox.
div {
display: table;
border-collapse: separate;
}
div {
display: table;
border-collapse: separate;
border-spacing: 20px 5px;
}
div {
display: table;
empty-cells: hide;
}
div {
display: table;
caption-side: bottom;
}


Distribution par défaut
La disposition des éléments d’un tableau se fait sous la forme d’un quadrillage composé de rangées et de colonnes.
Les éléments internes d’une table n’ont pas de marges externes (margin), et les éléments de rangées ne disposent pas non plus de marges internes (padding).
Distribution verticale
Les rangées remplissent l’ensemble de la table, du haut vers le bas dans l’ordre de leur apparition dans le code source.
Chaque cellule d’une même rangée s’adapte automatiquement à la hauteur de la cellule la plus haute, pour occuper toute la hauteur de la rangée.

Distribution horizontale
Les cellules d’une rangée remplissent l’ensemble de l’espace de leur rangée, de la gauche vers la droite dans l’ordre d’apparition dans le code HTML (sauf si la propriété direction est appliquée sur le tableau).
Une cellule ne peut pas recouvrir une autre cellule et ne peut pas s’étendre au-delà de sa rangée.



Alignement vertical
Les cellules de tableau HTML (<td>) sont réputées pour bénéficier d’un avantage tenant du Saint Graal du concepteur web : pouvoir appliquer la propriété vertical-align et en tirer toutes les vertus en termes d’alignement vertical des contenus.
Qu’à cela ne tienne ! vertical-align est parfaitement adéquate pour le modèle tabulaire CSS et peut être affectée à un élément en display: table-cell pour en aligner le contenu.
Un vieux rêve d’intégrateur web se réalise sous nos yeux : celui de pouvoir intuitivement centrer verticalement n’importe quel élément en HTML.
div {
display: table-cell;
vertical-align: middle;
}

Les valeurs acceptées pour l’alignement vertical sont :
baseline- La ligne de base de la cellule se place à la même hauteur que celle de la première rangée dans laquelle celle-ci s'étend.
top- Le haut de la boîte de la cellule s'aligne sur le haut de la première rangée dans laquelle celle-ci s'étend.
bottom- Le bas de la boîte de la cellule s'aligne sur celui de la dernière rangée dans laquelle celle-ci s'étend.
middle- Le milieu de la cellule s'aligne sur celui des rangées dans lesquelles celle-ci s'étend.
sub, super, text-top, text-bottom- Ces valeurs ne s'appliquent pas aux cellules ; pour ces valeurs, la cellule s'aligne sur la ligne de base (
baseline) à la place.
Plus d’informations : Comment aligner verticalement une image et une ligne de texte
Flux et ordre d'affichage
Certaines valeurs spécifiques du modèle d’affichage sous forme de tableau modifient l’ordre d’affichage des éléments empilés verticalement :
- Un élément déclaré en
table-header-groupse placera avant ses frères. - Un élément en
table-footer-groupse positionnera à la suite de ses frères. - Un élément en
table-captionapparaîtra par défaut tout en haut de la pile, mais peut être déplacé tout en bas s’il est accompagné d’une déclarationcaption-side: bottom.
Illustration : un élément en table-caption s'affiche avant son frère, la boîte anonyme table construite autour des 3 blocks :

Affublé d'un caption-side: bottom, l'élément table-caption se place en dessous :

Des éléments table-header-group et table-footer-group s'affichent ainsi :

Les éléments anonymes
Chaque élément de rendu tableau en CSS crée automatiquement des objets de table anonymes autour de lui-même, c’est-à-dire que les éléments de structure manquants sont créés par le navigateur.
Ce concept est assez complexe à appréhender et pourtant essentiel pour bien comprendre les subtilités des positionnements tabulaires.
Construction anonyme descendante :
- Si le parent d’éléments frères
table-celln’est pas untable-row, alors un objet anonymetable-rowest créé autour des frèrestable-cell - Si le parent d’éléments frères
table-row(ou équivalent) n’est pas untable, alors un objet anonymetableest créé autour des frèrestable-rowou équivalents
Illustration : un élément table-cell construit autour de lui un objet table-row et table, ses frères blocks ne sont pas concernés :

Un objet table-row + table se construit autour de 2 frères table-cell :

Même schéma pour trois frères puis quatre frères (illustrations ci-dessous) :


Construction anonyme ascendante :
-
Un parent
table(ou équivalent) construit un objet anonymetable-rowautour de l'ensemble de ses enfants directs qui ne sont pastable-rowou équivalents -
Un parent
table-row(ou équivalent) construit un objet anonymetable-cellautour de l'ensemble de ses enfants directs qui ne sont pastable-cell
Illustration : un parent table construit autour des 4 blocks un objet table-cell + table-row :

Un des éléments est un table-cell ; autour des 3 blocks frères se construit un table-cell également, puis un table-row se contruit autour des 2 table-cell (celle de gauche et celle - anonyme - de droite) :

Dans les illustrations suivantes, un élément table-cell anonyme est construit autour des éléments frères blocks, puis un table-row anonyme se construit autour des cellules réelles ou imaginaires :



Spécificités des éléments tabulaires
Propriétés incompatibles
Les valeurs de rangées (display: table-row et équivalents) présentent des particularités liées à leur rendu :
table-rowne comprend pas la propriétépadding, nimargin,position, width, min/max-width, min/max-height, vertical-align, borderetoverflow.- Plus globalement, il n’est pas possible d’appliquer la propriété
paddingaux élément endisplay table-row-group, table-header-group, table-footer-group, table-row, table-column-groupettable-column. - Enfin, il ne peut y avoir qu’un seul
table-captionau sein d’un tableau.
Positionnement
Selon les spécifications, positionner ou rendre flottant une cellule de tableau *peut* modifier son comportement, ne plus être considérée comme une cellule et affecter l’alignement et les dimensions de la table.
En pratique, il n’est pas possible de faire bénéficier les éléments tabulaires de la position relative sur certains navigateurs (Firefox par exemple), ce qui peut être gênant puisqu’ils ne peuvent ainsi pas servir de référents pour des contenus positionnés en absolu.

L'élément «choucroute» est positionné en position: absolute à right: 0 et top: 0. Logiquement, il se positionne hors du tableau :

Lorsque le conteneur global (display: table) est en position: relative, il devient un référent pour «choucroute» :

Par contre, lorsque l'un des élements en display: table-cell est en position: relative, il ne devient pas un référent pour «choucroute» sur certains navigateurs.

Génération de contenu
Il est possible de générer du contenu en CSS sur des éléments tabulaires à l’aide des pseudo-éléments CSS3 ::before et ::after (ou leurs versions CSS2 :before et :after).
Particularité pittoresque : les éléments générés sont susceptibles de participer eux aussi au grand jeu de la construction d’objets anonymes (voir précédemment), et se voir inclus dans des éléments table-cell ou table-row.
Illustration : des éléments générés devant et derrière le contenu de l'enfant table-cell :

div {display: table}
div:before {
content: "div:before";
display: table-cell;
width: 33%;
padding: 3px;
background: orange;
}
div:after {
content: "div:after";
display: table-cell;
width: 33%;
padding: 3px;
background: #39f;
}
Si les éléments sont générés directement sur le parent en display: table, alors un objet anonyme table-cell se crée autour de chacun des éléments individuels générés en :before et :after :

Si les éléments générés sont eux-mêmes en display: table-cell, ils participent avec leur troisième frère table-cell à la construction d'un conteneur anonyme commun table-row :

Considérations d'accessibilité
Quelques tests de lecteurs d’écran ont révélé que certains outils d’accessibilité traitent les éléments en display: table (et variantes) comme de vrais éléments tablulaires HTML, même s’il s’agit de div ou de paragraphes.
Cela peut créer des gênes, voire des soucis d’accessibilité, lorsque ces éléments sont porteurs de sens tels que des éléments de navigation par exemple ou des niveaux de titres.
Aux dernières nouvelles, la grande majorité (Window-eye, Jaws, Voice-over et NVDA sur IE) se comportent correctement. Le problème (s'il s'agit vraiment d'un problème) n'apparaît que sur certains dispositifs tels que NVDA sur Firefox et ORCA.
Plus d’information :
Using display:table has semantic effects in some screen readers
Conclusion
Avec ses avantages et inconvénients, le modèle tabulaire en CSS répond à des besoins de constructions que l'on peut rencontrer quotidiennement dans notre métier d'intégrateur.
Trop souvent laissé pour compte en raison du lourd passé de ses cousins (les <table> HTML), le positionnement CSS via display mérite aujourd'hui toute notre attention, depuis la mort programmée des anciennes versions d'Internet Explorer, même si tous nos maux ne seront pas résolus en un coup de… pinceau !
En tout cas, j'espère que vous ne pourrez plus dire désormais que «je n'y comprends rien aux tableaux CSS»…
Ressources
- Spécifications officielles CSS2.1
- Alternative à table-cell pour IE6 et IE7
- Conférence à Paris-Web 2011 sur les tableaux de mise en page
- Livre de Sitepoint «Everything You Know About CSS Is Wrong!» (Rachel Andrew & Kevin Yanks, SitePoint, 2008)

Vos commentaires
# Nico Le 11 septembre 2013 à 16:28
Merci pour cet article vraiment très instructif et très détaillé. C’est exactement ce qu’il me fallait pour enfin me mettre à jour avec les display.
Adieu les float !
# Long Lazuli Le 10 mars 2015 à 14:08
Chouette article !
Nous avons appris à séparer la sémantique de la présentation,
mais il y a des cas ou la présentation que nous cherchons est proche d’un tableau !
Je vous propose un exemple d’utilisation :
http://codepen.io/long-lazuli/pen/auFyz
: : Afficher des lignes autour de titres sans ajouter des éléments ni modifier la sémantique.
Vos commentaires
Suivre les commentaires :
|
