Niveau 12

Les Tableaux

Maîtriser les tableaux HTML et leur stylisation CSS pour présenter des données structurées de manière professionnelle.

1. Le concept fondamental

En une phrase : Un tableau HTML (<table>) sert à présenter des données tabulaires — des informations organisées en lignes et colonnes.

Les tableaux sont l'un des éléments les plus anciens du HTML. Contrairement aux listes (qui sont linéaires) ou aux grilles CSS (qui sont des mises en page), un tableau est conçu pour des données structurées : comparaisons, classements, emplois du temps, matrices de données.

Quand utiliser un tableau ?

Erreur fréquente : Ne pas utiliser les tableaux pour la mise en page ! Les tableaux de mise en page (design table-based) sont une pratique obsolète depuis plus de 20 ans. Utilisez Flexbox ou CSS Grid pour la mise en page.

Structure anatomique d'un tableau

<table>
  <caption>Titre du tableau</caption>
  <thead>
    <tr>
      <th>En-tête 1</th>
      <th>En-tête 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Donnée 1</td>
      <td>Donnée 2</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td>Pied 1</td>
      <td>Pied 2</td>
    </tr>
  </tfoot>
</table>

Anatomie complète d'un tableau HTML sémantique

2. Syntaxe et propriétés CSS

Les balises du tableau

Balise Rôle Description
<table> Conteneur Élément racine du tableau
<caption> Titre Titre sémantique du tableau (accessibilité)
<thead> En-tête Groupe de lignes d'en-tête
<tbody> Corps Groupe de lignes de données principales
<tfoot> Pied Groupe de lignes de résumé/pied
<tr> Ligne Une ligne du tableau
<th> Cellule d'en-tête Cellule d'en-tête (gras + centré par défaut)
<td> Cellule Cellule de données standard

Propriétés CSS essentielles

Propriété Valeurs Effet
border-collapse separate | collapse Fusionne ou sépare les bordures des cellules
border-spacing Valeurs de longueur Espace entre les cellules (avec separate)
table-layout auto | fixed Algorithme de calcul de la largeur des colonnes
vertical-align top | middle | bottom Alignement vertical du contenu dans les cellules
text-align left | center | right Alignement horizontal du texte dans les cellules
width Pourcentage, px, auto Largeur du tableau

border-collapse

La propriété border-collapse contrôle la fusion des bordures entre les cellules adjacentes :

/* Par défaut : les bordures sont séparées */
table {
  border-collapse: separate;
  border-spacing: 8px;  /* espace entre cellules */
}

/* Bordures fusionnées (le plus courant) */
table {
  border-collapse: collapse;
}

table-layout

/* Calcul automatique basé sur le contenu (lent) */
table {
  table-layout: auto;
}

/* Largeur fixe basée sur la première ligne (rapide) */
table {
  table-layout: fixed;
  width: 100%;
}
Astuce : table-layout: fixed est beaucoup plus rapide pour les grands tableaux car le navigateur n'a pas besoin d'analyser tout le contenu pour calculer les largeurs. Les colonnes prennent une largeur proportionnelle égale (sauf si spécifié avec width).

3. Visualisation

border-collapse : separate vs collapse

separate

Cellule
Cellule
Cellule
Cellule
Cellule
Cellule

collapse

Cellule
Cellule
Cellule
Cellule
Cellule
Cellule

Comparaison visuelle : separate (gauche) garde l'espacement entre cellules, collapse (droite) fusionne les bordures

vertical-align dans les cellules

Valeur Rendu
top Texte aligné en haut de la cellule. Ceci est un texte assez long pour montrer l'alignement vertical.
middle Texte centré verticalement dans la cellule.
bottom Texte aligné en bas de la cellule.

4. Exemples progressifs

Exemple 1 — Tableau de base stylisé

<table class="table-base">
  <thead>
    <tr>
      <th>Langage</th>
      <th>Année</th>
      <th>Paradigme</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JavaScript</td>
      <td>1995</td>
      <td>Multi-paradigme</td>
    </tr>
    <tr>
      <td>Python</td>
      <td>1991</td>
      <td>Orienté objet</td>
    </tr>
  </tbody>
</table>

Rendu :

Langage Année Paradigme Popularity
JavaScript 1995 Multi-paradigme ⭐⭐⭐⭐⭐
Python 1991 Orienté objet ⭐⭐⭐⭐⭐
TypeScript 2012 Multi-paradigme ⭐⭐⭐⭐
Rust 2010 Système / Fonctionnel ⭐⭐⭐
Go 2009 Impératif ⭐⭐⭐⭐

Exemple 2 — Bandes de zébrage avec :nth-child()

/* Zébrage des lignes paires */
.table-zebra tbody tr:nth-child(even) {
  background-color: #f1f5f9;
}

.table-zebra tbody tr:nth-child(odd) {
  background-color: #ffffff;
}

/* Effet de survol */
.table-zebra tbody tr:hover {
  background-color: #e0f2fe;
}

Rendu :

# Nom Email Rôle Statut
001 Alice Martin Développeuse Actif
002 Bob Dupont Designer Actif
003 Claire Leroy Chef de projet En attente
004 David Moreau Développeur Inactif
005 Emma Bernard DevOps Premium
006 François Petit Développeur Actif

Exemple 3 — En-tête sticky (épinglé)

.table-scroll-wrapper {
  max-height: 300px;
  overflow-y: auto;
}

.table-sticky thead th {
  position: sticky;
  top: 0;
  background-color: #2563eb;
  color: white;
  z-index: 1;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

Rendu :

ID Nom du projet Statut Progression
PRJ-001Refonte site e-commerceEn cours78%
PRJ-002Application mobile iOSEn attente12%
PRJ-003Migration base de donnéesEn cours95%
PRJ-004Dashboard analyticsEn cours45%
PRJ-005API REST v2Terminé100%
PRJ-006Système de notificationsEn attente0%
PRJ-007Tests d'intégrationEn cours60%
PRJ-008Documentation APIEn cours33%
PRJ-009Mise en productionPlanifié0%
PRJ-010Audit de sécuritéEn cours88%

Exemple 4 — Tableau responsive mobile

/* Sur mobile, chaque ligne devient une "carte" */
@media (max-width: 600px) {
  .table-block table,
  .table-block thead,
  .table-block tbody,
  .table-block tr,
  .table-block th,
  .table-block td {
    display: block;
  }

  /* Cache les en-têtes */
  .table-block thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }

  .table-block td {
    display: flex;
    justify-content: space-between;
    padding: 0.5rem 1rem;
  }

  /* Utilise data-label pour le nom de la colonne */
  .table-block td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--couleur-texte-clair);
  }
}

Rendu :

Service Prix/mois Utilisateurs Statut
Essentiel 9,99 € 1 Actif
Professionnel 29,99 € 10 Actif
Entreprise 79,99 € Illimité En attente

Exemple 5 — Design moderne avec design de table

Rendu :

Employé Département Localisation Statut Performance
AM
Alice Martin
Ingénierie Paris En poste ⭐⭐⭐⭐⭐
BD
Bob Dupont
Design Lyon En poste ⭐⭐⭐⭐
CL
Claire Leroy
Marketing Marseille En mission ⭐⭐⭐⭐
DM
David Moreau
Support Toulouse Congé ⭐⭐⭐

Exemple 6 — Tableau avec indicateurs de tri

.table-sort th {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: 2rem;
}

.table-sort th .sort-icon {
  position: absolute;
  right: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
}

.table-sort th.sorted-asc .sort-icon::after {
  content: "▲";   /* Flèche tri ascendant */
}

.table-sort th.sorted-desc .sort-icon::after {
  content: "▼";   /* Flèche tri descendant */
}

Rendu :

Nom Population Superficie Densité
Paris 2 161 000 105,4 km² 20 503 hab/km²
Marseille 873 000 240,6 km² 3 628 hab/km²
Lyon 522 000 47,8 km² 10 920 hab/km²
Toulouse 498 000 118,3 km² 4 210 hab/km²
Nice 340 000 71,9 km² 4 729 hab/km²

Exemple 7 — Tableau avec badges de statut colorés

Rendu :

Commande Client Montant Date Statut
#CMD-20451 Sophie Durand 249,00 € 15/07/2026 Livrée
#CMD-20452 Marc Laurent 89,50 € 16/07/2026 En cours
#CMD-20453 Julie Rousseau 412,00 € 16/07/2026 En préparation
#CMD-20454 Thomas Girard 67,80 € 17/07/2026 Annulée
#CMD-20455 Camille Bonnet 156,25 € 17/07/2026 VIP

Exemple 8 — Tableau comparatif de tarification

Rendu :

Gratuit Pro ★ Entreprise
Prix 0 € 19 €/mois 79 €/mois
Espace stockage 1 Go 100 Go Illimité
Utilisateurs 1 10 Illimité
Support Communauté Email 24/7 Téléphone
Analytics Basique Avancé
API REST REST + GraphQL
SLA 99,9%

Exemple 9 — Tableau calendrier

Rendu :

Lu Ma Me Je Ve Sa Di
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2

Exemple 10 — Contrôle des colonnes avec <col>

<table class="table-fixed">
  <colgroup>
    <col class="col-narrow">    
    <col class="col-wide">      
    <col class="col-medium">    
  </colgroup>
  ...
</table>

Rendu :

ID Description Catégorie
#A1 Bandeau de navigation responsive avec menu hamburger Composant UI
#B2 Formulaire de contact avec validation côté client Formulaire
#C3 Grille de produits e-commerce avec filtres Layout

5. Erreurs fréquentes

Erreur n°1 — Utiliser les tableaux pour la mise en page

Les tableaux de mise en page (display: table sur des divs non tabulaires) sont une pratique obsolète. Utilisez Flexbox ou CSS Grid à la place.

/* ❌ MAUVAIS — Tableau de mise en page */
<table>
  <tr>
    <td>Logo</td>
    <td>Menu</td>
    <td>Recherche</td>
  </tr>
</table>

/* ✅ BON — Flexbox pour la mise en page */
<header style="display: flex; align-items: center;">
  <div class="logo">...</div>
  <nav class="menu">...</nav>
  <div class="recherche">...</div>
</header>
Erreur n°2 — Omettre <thead>, <tbody>, <tfoot>

Ces éléments sémantiques sont essentiels pour l'accessibilité et permettent le positionnement sticky des en-têtes.

/* ❌ MAUVAIS — Sans structure sémantique */
<table>
  <tr><th>Nom</th><th>Âge</th></tr>
  <tr><td>Alice</td><td>25</td></tr>
</table>

/* ✅ BON — Avec structure complète */
<table>
  <thead>
    <tr><th>Nom</th><th>Âge</th></tr>
  </thead>
  <tbody>
    <tr><td>Alice</td><td>25</td></tr>
  </tbody>
</table>
Erreur n°3 — Oublier le <caption>

Le <caption> fournit un titre accessible au tableau. Les technologies d'assistance ( lecteurs d'écran ) l'utilisent pour annoncer le contenu du tableau.

Erreur n°4 — Utiliser border="1" au lieu du CSS

L'attribut HTML border="1" est déprécié. Utilisez toujours CSS pour les bordures.

/* ❌ MAUVAIS */
<table border="1">

/* ✅ BON */
<table>
  <style>
    table { border-collapse: collapse; }
    th, td { border: 1px solid #ccc; }
  </style>
</table>
Erreur n°5 — Ne pas gérer le débordement sur mobile

Un large tableau sur petit écran déborde et casse la mise en page. Utilisez overflow-x: auto ou convertissez le tableau en carte.

/* ✅ Solution 1 : Défilement horizontal */
.table-responsive-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ✅ Solution 2 : Conversion en blocs sur mobile */
@media (max-width: 600px) {
  table, thead, tbody, tr, th, td {
    display: block;
  }
  thead { /* Accessibilité : masquer visuellement */ }
  td::before { content: attr(data-label); }
}
Erreur n°6 — Oublier que border-collapse empêche border-radius sur les cellules

Quand border-collapse: collapse est actif, border-radius ne fonctionne pas sur les <td> et <th>. Il faut utiliser separate pour obtenir des coins arrondis.

6. Bonnes pratiques

Bonne pratique n°1 — Utiliser border-collapse: collapse par défaut

C'est le style le plus courant et le plus propre. Les bordures fusionnées donnent un aspect professionnel.

Bonne pratique n°2 — Toujours utiliser <thead>, <tbody>, <tfoot>

Même si le rendu visuel est identique, ces éléments sont essentiels pour l'accessibilité et permettent des styles ciblés (sticky header, zébrage limité au tbody...).

Bonne pratique n°3 — Ajouter un <caption>

Chaque tableau doit avoir un titre. C'est une exigence WCAG pour l'accessibilité.

Bonne pratique n°4 — Utiliser :nth-child() pour le zébrage

Le zébrage améliore la lisibilité des longs tableaux. Appliquez-le sur <tbody> pour éviter de zébrer l'en-tête.

Bonne pratique n°5 — Préférer table-layout: fixed pour les performances

Si vos colonnes ont des largeurs connues, fixed est beaucoup plus rapide car le navigateur n'a pas besoin de parcourir tout le contenu.

Bonne pratique n°6 — Utiliser les attributs scope et headers

Pour les tableaux complexes, les attributs HTML scope et headers aident les lecteurs d'écran à associer les données aux en-têtes.

<th scope="col">Nom</th>     <!-- Colonne entière -->
<th scope="row">Total</th>    <!-- Ligne entière -->
Bonne pratique n°7 — Gérer le responsive

Tout tableau doit être consultable sur mobile. Soit par défilement horizontal contrôlé, soit par conversion en layout carte.

Bonne pratique n°8 — Ajouter un padding suffisant dans les cellules

Les cellules comprimées sont illisibles. Un minimum de 0.75rem 1rem est recommandé.

7. Mini-défi

Défi n°1 — Tableau de scores

Objectif : Créer un tableau de classement de joueurs avec :

  • Un en-tête avec zébrage sur le <tbody>
  • Des badges de statut colorés (En ligne, Hors ligne, En jeu)
  • Un en-tête sticky
  • Un style responsive qui passe en mode carte sur mobile

Défi n°2 — Tableau de comparaison de produits

Objectif : Créer un tableau comparatif avec :

  • Des colonnes avec table-layout: fixed
  • Des icônes ✓/✗ pour les fonctionnalités
  • Une colonne mise en avant avec un style spécial
  • Un <caption> pour l'accessibilité

Défi n°3 — Mini calendrier mensuel

Objectif : Créer un calendrier avec :

  • Les jours de la semaine en en-tête
  • Le jour actuel surligné
  • Les jours du mois précédent/followant en semi-transparent
  • Un effet de survol sur les cases

8. Projet — Dashboard de données

Consigne :

Créez un tableau de bord de données complet qui combine les concepts vus dans ce chapitre :

  1. Un tableau principal avec en-tête sticky, zébrage, et badges de statut
  2. Un tableau comparatif de tarification avec colonne mise en avant
  3. Un calendrier mensuel avec le jour actuel surligné
  4. Le tout doit être 100% responsive : scroll horizontal sur tablette, conversion en carte sur mobile
  5. Ajoutez un <caption> et des attributs scope pour l'accessibilité

9. Révision

Récapitulatif des concepts clés

Concept Propriété / Élément Utilisation
Structure <table>, <thead>, <tbody>, <tfoot>, <tr>, <th>, <td>, <caption> Anatomie sémantique du tableau
Fusion des bordures border-collapse collapse (fusionné) ou separate (espacé)
Espacement border-spacing Espace entre cellules (avec separate)
Algorithme de layout table-layout auto (calculé) ou fixed (première ligne)
Alignement vertical vertical-align top, middle, bottom dans les cellules
Zébrage :nth-child(even/odd) Lignes alternées pour la lisibilité
En-tête fixe position: sticky En-tête qui reste visible au défilement
Responsive overflow-x: auto ou conversion display: block Adaptation mobile des tableaux larges
Accessibilité <caption>, scope Titre et liaisons en-tête-cellule
Largeur colonnes <col>, <colgroup> Contrôle de la largeur sans affecter le contenu

Quiz rapide

  1. Quelle propriété empêche border-radius de fonctionner sur les cellules ?
  2. Quel élément HTML fournit le titre sémantique d'un tableau ?
  3. Quelle est la différence entre table-layout: auto et fixed ?
  4. Pourquoi faut-il appliquer le zébrage sur <tbody> plutôt que sur le tableau entier ?
  5. Comment masquer visuellement les en-têtes tout en les gardant accessibles ?
Réponses :
  1. border-collapse: collapse
  2. <caption>
  3. auto calcule selon le contenu (lent), fixed selon la première ligne (rapide)
  4. Pour ne pas zébrer les lignes d'en-tête
  5. Avec clip: rect(0,0,0,0) et position: absolute (clip-path ou sr-only)

Cheat sheet

/* Tableau de base */
table {
  width: 100%;
  border-collapse: collapse;
}

/* Zébrage */
tbody tr:nth-child(even) {
  background-color: #f1f5f9;
}

/* En-tête sticky */
thead th {
  position: sticky;
  top: 0;
  background: #2563eb;
  z-index: 1;
}

/* Wrapper responsive */
.table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Conversion mobile */
@media (max-width: 600px) {
  table, thead, tbody, tr, th, td {
    display: block;
  }
  td::before { content: attr(data-label); font-weight: 600; }
}