CSS Grid & Flexbox — Référence
Propriétés, modèles de positionnement et guide de décision pour les deux systèmes de mise en page CSS modernes.
Cette page est un complément à
layout-patterns.mdx(motifs concrets) et à la section CSS deindex.mdx(vue d’ensemble). Elle couvre les concepts avancés absents des deux pages.
Choisir Grid ou Flexbox
| Critère | Flexbox | Grid |
|---|---|---|
| Dimension principale | 1D (ligne OU colonne) | 2D (lignes ET colonnes simultanément) |
| Cas idéal | Barres de navigation, boutons groupés, alignment interne d’un composant | Mise en page globale de page, carrousels, dashboards |
| Taille des items | Détermine la taille du conteneur | Le conteneur détermine la taille des items |
| Ordre visuel | order (facile) | grid-area (précis) |
| Lignes nommées | Non | grid-template-columns: [sidebar-start] 240px [sidebar-end] 1fr [main-end] |
| Sous-grille | Non | grid-template-rows: subgrid |
Règle pratique : utiliser Grid pour la structure globale de la page, Flexbox pour aligner les éléments à l’intérieur de chaque cellule ou composant.
Flexbox — Modèle d’axes
Flexbox manipule deux axes. Tout comprendre sur les axes évite 80 % des erreurs d’alignement.
→ flex-direction: row (par défaut)
┌─────────────────────────────────────────────┐
│ │ │ │ ←─ main-axis (axe principal) │
│ │ │ │ ↑ cross-axis │
└─────────────────────────────────────────────┘
← flex-direction: row-reverseValeur flex-direction | main-axis | cross-axis |
|---|---|---|
row (défaut) | horizontale ←→ | verticale ↑↓ |
row-reverse | horizontale →← | verticale ↑↓ |
column | verticale ↑↓ | horizontale ←→ |
column-reverse | verticale ↓↑ | horizontale ←→ |
Alignement sur les axes
.container {
display: flex;
/* Axe principal (selon flex-direction) */
justify-content: center; /* center | flex-start | flex-end | space-between | space-around | space-evenly */
/* Axe perpendiculaire */
align-items: center; /* flex-start | center | flex-end | stretch | baseline */
/* Si wrap et que les lignes n'occupent pas toute la hauteur */
align-content: center; /* pareil que align-items, mais par LIGNE */
}Piège :
align-contentn’a d’effet que siflex-wrap: wrapest activé et que les lignes n’occupent pas toute la hauteur du conteneur. Dans tous les autres cas, c’estalign-itemsqui agit.
Alignement par item (align-self, justify-self)
Un item peut être aligné indépendamment des autres :
.item--top { align-self: flex-start; }
.item--center { align-self: center; }
.item--bottom { align-self: flex-end; }
.item--stretch { align-self: stretch; }Piège :
align-self: stretch(valeur par défaut) pousse l’item à occuper toute la hauteur. Si l’item aheight: auto, cette propriété est invisible. Donner uneheightexplicite oumin-heightrévèle l’effet.
order — Ordonner sans toucher au HTML
.item--first { order: -1; }
.item--second { order: 2; }
/* L'ordre visuel ne change PAS l'ordre du DOM, ni la tabulation clavier */Flex shorthand : décrypter flex: 1 1 200px
.flex-item {
/* flex-grow | flex-shrink | flex-basis */
flex: 1 1 200px;
}| Valeur | Signification |
|---|---|
flex: 1 | 1 1 0% — pousse à remplir l’espace restant, taille de base = 0 |
flex: 0 1 200px | Ne grandit pas, peut rétrécir depuis 200px |
flex: 0 0 200px | Taille fixe de 200px, ne grandit ni ne rétrécit |
flex: none | 0 0 auto — taille intrinsèque, ne grandit ni ne rétrécit |
flex: auto | 1 1 auto — grandit et rétrécit, taille de base = contenu |
Piège :
flex: 0 0 100%ne veut pas dire 100 % de la largeur.flex-basis: 100%est bien de 100 % du parent, mais si un item aflex: 0 0 100%et qu’il y en a 2, ils se déborderont mutuellement.
Grid — Concepts avancés
Grille implicite vs explicite
.container {
display: grid;
/* Grille EXPLICITE : les pistes sont déclarées */
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
/* Les items qui dépassent créent des pistes IMPLICITES */
}Grille explicite 3×1 + 4 items
┌─────┬─────┬─────┐
│ 1 │ 2 │ 3 │ ← pistes explicites
├─────┤ │ │
│ 4 │ │ │ ← item 4 crée une 2e ligne implicite
└─────┴─────┴─────┘Piège : sans
grid-template-rowsdéclaré, les lignes implicites prennent la hauteur minimale (auto). Un contenu long dans le 4e item déborde au-delà des 3 premières pistes. Fixergrid-auto-rows: 100pxpour contrôler.
grid-template-areas avec mapping ASCII
.dashboard {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header header"
"sidebar main aside"
"sidebar footer footer";
min-height: 100dvh;
}
.sidebar-nav { grid-area: sidebar; }
.header { grid-area: header; }
.main-content { grid-area: main; }
.sidebar { grid-area: aside; }
.footer { grid-area: footer; }Piège : une zone nommée doit être un rectangle. On ne peut pas avoir une zone en
Lou enT. Si une cellule reste vide, utiliser.(point) à la place du nom.
Positionnement avec des lignes nommées
.container {
display: grid;
grid-template-columns:
[sidebar-start] 240px [sidebar-end content-start] 1fr [content-end];
grid-template-rows: [top] auto [mid] 1fr [bottom];
}
.card--featured {
/* Placer entre les lignes nommées */
grid-column: content-start / content-end;
grid-row: mid / bottom;
}subgrid — Hériter des pistes du parent
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.card {
display: grid;
grid-template-rows: subgrid; /* Hérite les lignes du parent */
row-gap: 0.5rem;
}
.card h2 { grid-row: 1; }
.card p { grid-row: 2; }
.card .meta{ grid-row: 3; }
.card .img { grid-row: 4; }Piège :
subgridhérite uniquement des pistes du parent dans la même direction. Utilisergrid-template-columns: subgridetgrid-template-rows: subgridséparément.
grid-auto-flow
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* default: row — remplit chaque ligne de gauche à droite */
grid-auto-flow: row;
/* dense — remplit les trous, mais peut réordonner les items */
grid-auto-flow: row dense;
/* column — remplit chaque colonne de haut en bas */
grid-auto-flow: column;
/* diagonal — remplit diagonalement (rare) */
grid-auto-flow: diagonal;
}Auto-placement intelligent avec auto-rows / auto-columns
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 100px; /* Taille des lignes créées dynamiquement */
gap: 1rem;
}Pièges Grid / Flexbox récurrents
| Piège | Symptôme | Correction |
|---|---|---|
align-items: stretch sur un item sans hauteur | Item invisible ou coupé | Ajouter height: auto ou min-height |
gap entre deux conteneurs imbriqués | Espace inattendu au niveau de la bordure | gap agit entre les items, pas entre les conteneurs |
flex-shrink: 0 + min-width conflictuel | L’item refuse de rétrécir même avec overflow: hidden | Définir min-width: 0 sur l’item flex pour autoriser le rétrécissement |
grid-auto-flow: dense réordonne les items | Un item se retrouve à un endroit inattendu | Retirer dense si l’ordre HTML doit être respecté |
grid-area sans grid-template-areas | La zone est ignorée | Déclarer les zones dans grid-template-areas du parent |
subgrid sur une grille sans lignes définies | Erreur de rendu, les enfants sont empilés | Le parent doit avoir grid-template-rows (ou -columns) déclaré |
100% dans un item flex avec border-box | L’item déborde du conteneur | Utiliser width: 0 et flex: 1 à la place de width: 100% |
gap sur un item grid | Espace créé entre l’item et le conteneur | gap ne s’applique qu’au conteneur, pas à un item grid |
Résumé rapide : quand utiliser quoi
Nouvelle mise en page ?
│
├─ Structure de page complète (header, nav, main, footer) ?
│ → Grid
│
├─ Alignement horizontal/vertical simple (boutons, badges, icônes) ?
│ → Flexbox
│
├─ Carrousel, tabs, filtres horizontaux ?
│ → Flexbox
│
├─ Dashboard, grille de cartes responsive ?
│ → Grid
│
└─ Les deux ?
→ Grid pour la structure, Flexbox à l'intérieur de chaque cellule