Prérequis
- Niveau : avoir vu Flexbox (cf. notre tuto Flexbox) et Grid (cf. notre tuto Grid) séparément.
- Outils : VS Code + Live Server, navigateur moderne (DevTools : Grid Inspector + Flexbox Inspector).
- Temps estimé : 1 h.
Pourquoi combiner Flexbox et Grid ?
Grid et Flexbox ne sont pas concurrents. Grid règle la structure 2D (lignes ET colonnes), Flexbox règle l’alignement 1D (ligne OU colonne) à l’intérieur de chaque cellule. Combinés, ils couvrent 100 % des besoins de layout sans recourir aux frameworks lourds.
Flexbox vs Grid : quand utiliser quoi
Flexbox et CSS Grid ne sont pas en compétition — ils sont complémentaires. La règle simple :
- Flexbox = alignement sur un axe (horizontal OU vertical). Idéal pour : barres de navigation, groupes de boutons, centrage, distribution d’éléments dans un conteneur
- CSS Grid = placement sur deux axes (lignes ET colonnes). Idéal pour : mises en page complètes, grilles de cartes, layouts complexes avec des zones nommées
En pratique, vous utilisez Grid pour la structure générale de la page et Flexbox pour l’alignement à l’intérieur de chaque section.
Rappel Flexbox : les propriétés essentielles
/* Conteneur flex */
.container {
display: flex;
justify-content: space-between; /* Axe principal (horizontal par défaut) */
align-items: center; /* Axe secondaire (vertical) */
gap: 16px; /* Espace entre les éléments */
flex-wrap: wrap; /* Retour à la ligne si pas de place */
}
/* Enfants flex */
.item {
flex: 1; /* Prend une part égale de l'espace */
flex: 0 0 200px; /* Taille fixe de 200px, ne grandit/rétrécit pas */
flex: 1 1 300px; /* Part égale, min 300px, peut rétrécir */
}
Rappel Grid : les propriétés essentielles
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 colonnes égales */
grid-template-columns: 250px 1fr 300px; /* Sidebar - contenu - aside */
gap: 20px;
}
/* Responsive automatique sans media query */
.grid-auto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
repeat(auto-fit, minmax(280px, 1fr)) crée autant de colonnes que possible avec un minimum de 280px chacune. La grille passe automatiquement de 3 colonnes sur desktop à 1 colonne sur mobile.
Exemple 1 : Layout de page complet
<div class="page-layout">
<header class="header">Logo et navigation</header>
<aside class="sidebar">Menu latéral</aside>
<main class="content">Contenu principal</main>
<aside class="widgets">Widgets</aside>
<footer class="footer">Pied de page</footer>
</div>
/* Grid pour la structure de page */
.page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar content widgets"
"footer footer footer";
grid-template-columns: 250px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 0;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.widgets { grid-area: widgets; }
.footer { grid-area: footer; }
/* Flexbox pour la navigation DANS le header */
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
/* Responsive : passer à une colonne */
@media (max-width: 768px) {
.page-layout {
grid-template-areas:
"header"
"content"
"sidebar"
"widgets"
"footer";
grid-template-columns: 1fr;
}
}
Exemple 2 : Carte produit (Grid + Flexbox)
.products-grid {
/* Grid pour disposer les cartes */
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
.product-card {
/* Flexbox pour organiser l'intérieur de la carte */
display: flex;
flex-direction: column;
border: 1px solid #e0e0e0;
border-radius: 12px;
overflow: hidden;
}
.product-card img {
width: 100%;
aspect-ratio: 4/3;
object-fit: cover;
}
.product-info {
padding: 16px;
flex: 1; /* Prend l'espace restant */
display: flex;
flex-direction: column;
}
.product-info h3 { margin-bottom: 8px; }
.product-info p { flex: 1; color: #666; } /* Pousse le prix vers le bas */
.product-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 12px;
}
.product-price { font-size: 1.3rem; font-weight: bold; color: #e94560; }
.product-btn {
padding: 8px 16px;
background: #4a90d9;
color: white;
border: none;
border-radius: 6px;
}
L’astuce clé : flex: 1 sur la description pousse le prix et le bouton vers le bas de la carte. Toutes les cartes ont le même alignement vertical, quelle que soit la longueur de la description.
Exemple 3 : Barre de navigation responsive
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 24px;
background: #1a1a2e;
}
.nav-links {
display: flex;
gap: 24px;
list-style: none;
}
.nav-actions {
display: flex;
gap: 12px;
align-items: center;
}
@media (max-width: 768px) {
.navbar { flex-wrap: wrap; }
.nav-links {
order: 3; /* Passer en dessous */
width: 100%; /* Prendre toute la largeur */
flex-direction: column;
gap: 8px;
}
}
Aide-mémoire rapide
| Besoin | Utiliser | Propriété clé |
|---|---|---|
| Centrer un élément | Flex | display:flex; justify-content:center; align-items:center; |
| Grille de cartes | Grid | grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)) |
| Navigation horizontale | Flex | display:flex; gap:24px; align-items:center; |
| Layout de page | Grid | grid-template-areas |
| Sidebar fixe + contenu fluide | Grid | grid-template-columns: 250px 1fr |
| Boutons côte à côte | Flex | display:flex; gap:12px; |
| Footer collé en bas | Grid | grid-template-rows: auto 1fr auto |
Erreurs fréquentes
Tout faire en Grid (ou tout en Flex)
Cause : on apprend Grid et on l’applique partout, même pour aligner 3 boutons.
Solution : règle simple — Grid pour les conteneurs principaux (page, sections, grilles d’items), Flexbox pour les composants internes (navbar, card-footer, groupes de boutons).
Cartes de hauteur inégale dans une grille
Cause : Grid aligne les cartes mais leur contenu interne ne s’aligne pas (le bouton flotte au milieu).
Solution : sur la card, display: flex; flex-direction: column + sur la description flex: 1 → le bouton tombe en bas.
Confusion fr vs %
Cause : on utilise % qui ignore le gap.
Solution : utilisez fr (« fraction ») qui partage l’espace après avoir soustrait le gap.
Grille qui ne devient pas responsive sans media query
Cause : on fixe explicitement repeat(3, 1fr).
Solution : repeat(auto-fit, minmax(280px, 1fr)) s’adapte au nombre de colonnes selon la largeur, sans aucune media query.
Exercice
Construisez un tableau de bord avec :
- Un header avec logo + navigation (Flexbox)
- Une sidebar à gauche avec des liens (Flexbox vertical)
- Un contenu principal avec une grille de 4 cartes statistiques (Grid)
- Un graphique pleine largeur en dessous des cartes
- Le tout responsive : sidebar qui passe en haut sur mobile
Pour approfondir
- Maîtriser Flexbox en 10 exercices
- CSS Grid Layout
- Site responsive avec media queries
- Référence : web.dev — Learn CSS : Layout
- Outil visuel : CSS Grid Generator
Étape 1 — Poser la structure macro avec Grid
Sur une page web type tableau de bord ou site marchand à Dakar, Abidjan ou Cotonou, on commence toujours par dessiner la grille générale en CSS Grid. Grid excelle sur deux axes simultanés, c’est l’outil pour répartir header, sidebar, contenu et footer.
.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 64px 1fr 56px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
gap: 0;
}
.layout > header { grid-area: header; }
.layout > aside { grid-area: sidebar; }
.layout > main { grid-area: main; }
.layout > footer { grid-area: footer; }
Ce que vous devez voir : une page divisée en quatre zones nommées, le header occupe toute la largeur, la sidebar fait 240 px, le main prend le reste. Sur Chrome DevTools (onglet Layout), un overlay grille apparaît dès que le sélecteur .layout est inspecté — c’est le signal de réussite.
Étape 2 — Rendre la macro responsive avec une media query
En dessous de 768 px (mobile dominant en Afrique de l’Ouest, surtout sur les Tecno et Infinix), on bascule la sidebar sous le header pour libérer la largeur.
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"sidebar"
"main"
"footer";
}
}
Pourquoi cette approche : on ne change que grid-template-columns et grid-template-areas, pas la structure HTML. Vérifiez avec l’émulateur mobile de Chrome (F12 → Toggle device toolbar) : la sidebar passe sous le header sans repli HTML.
Étape 3 — Composer les cartes du main avec Flexbox
À l’intérieur du main, on liste des cartes (produits, articles, KPI). Ici Flexbox est plus adapté : on travaille sur un seul axe avec des éléments de tailles variables, et on veut que la dernière ligne ne s’étire pas bizarrement.
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 24px;
}
.cards > .card {
flex: 1 1 280px;
max-width: 360px;
background: #fff;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,.06);
}
La règle flex: 1 1 280px dit : grandis si tu peux, rétrécis si nécessaire, base 280 px. Combiné à flex-wrap: wrap, les cartes passent de 4 par ligne sur desktop à 1 par ligne sur smartphone, sans media query.
Étape 4 — Aligner précisément avec Grid à l’intérieur d’une carte
Quand une carte contient une icône à gauche, un titre, un sous-titre et un montant à droite (typique d’une fiche client ou d’un produit), Grid reprend la main pour des alignements pixel-perfect.
.card-stat {
display: grid;
grid-template-columns: 48px 1fr auto;
grid-template-rows: auto auto;
column-gap: 12px;
align-items: center;
}
.card-stat .icon { grid-row: 1 / 3; }
.card-stat .title { grid-column: 2; align-self: end; }
.card-stat .sub { grid-column: 2; align-self: start; color: #6b7280; }
.card-stat .amount { grid-column: 3; grid-row: 1 / 3; font-weight: 700; }
Pourquoi pas Flexbox ici : il faudrait imbriquer plusieurs conteneurs Flex pour obtenir l’alignement vertical de l’icône et du montant sur deux lignes. Grid résout ça avec grid-row: 1 / 3, sans markup superflu.
Étape 5 — Gérer un formulaire à deux colonnes avec auto-fit
Pour un formulaire d’inscription (paiement Mixx by Yas, Wave, Orange Money…), on veut deux colonnes sur tablette et plus, une seule sur mobile. repeat(auto-fit, minmax(...)) évite la moindre media query.
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 16px 24px;
}
.form-grid .full { grid-column: 1 / -1; }
Sur un écran de 1280 px, on aura 4 colonnes ; sur 768 px, 2 colonnes ; sur 360 px, 1 colonne. La classe utilitaire .full permet à un champ (CGU, bouton submit) de couvrir toute la largeur via grid-column: 1 / -1.
Étape 6 — Centrer un contenu modal en une ligne
Pour une modale de confirmation de paiement (montant en FCFA, par exemple 26 238 FCFA pour 40 EUR au taux fixe 1 EUR = 655,957 FCFA), Flexbox reste le moyen le plus court de centrer.
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,.5);
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
}
.modal-card {
background: #fff;
border-radius: 16px;
max-width: 480px;
width: 100%;
padding: 24px;
}
Trois lignes (display, align-items, justify-content) suffisent à centrer le contenu sur les deux axes. Avec Grid, place-items: center ferait le même travail en une ligne ; les deux approches sont équivalentes ici.
Étape 7 — Aligner verticalement un header avec Flexbox
Dans le header de la grille macro, on aligne le logo à gauche, la barre de recherche au centre, l’avatar et la cloche à droite.
.app-header {
display: flex;
align-items: center;
gap: 16px;
padding: 0 24px;
border-bottom: 1px solid #e5e7eb;
}
.app-header .search { flex: 1 1 auto; max-width: 480px; margin: 0 auto; }
.app-header .actions { display: flex; gap: 12px; margin-left: auto; }
L’astuce margin-left: auto sur .actions pousse les icônes à droite sans aucun positionnement absolu. Idéal pour rester maintenable quand l’équipe ajoute un bouton « Notifications ».
Étape 8 — Vérifier le rendu sur appareils ouest-africains
Avant déploiement, testez sur trois résolutions courantes en zone CFA : 360×800 (Tecno Spark, Infinix Hot), 412×915 (Samsung A05/A15), et 1366×768 (PC école/cybercafé). Dans Chrome DevTools, ajoutez ces tailles via « Edit » dans le menu Responsive.
Validation visuelle : aucune coupure horizontale, le texte des cartes reste lisible (≥14 px), les zones tactiles font au moins 44×44 px (recommandation iOS et Android). Pour creuser ce sujet, voyez aussi le tutoriel tableau de bord HTML/CSS/JS et le guide front-end principal.
Étape 9 — Régler les pièges classiques de combinaison
Pourquoi cette section : la majorité des bugs en production viennent d’erreurs récurrentes lorsque Grid contient du Flex et inversement. Voici les trois plus fréquents et leur correctif testé sur Chrome 130 et Firefox 132.
/* Bug 1 : le contenu d'une cellule grid déborde */
.layout > main {
min-width: 0; /* corrige le débordement horizontal */
min-height: 0;
}
/* Bug 2 : un enfant flex ne se rétrécit pas */
.cards > .card {
min-width: 0; /* permet à flex-shrink de fonctionner */
}
/* Bug 3 : alignement vertical en flex parent et grid enfant */
.app-header { align-items: stretch; }
.app-header > nav { display: grid; place-items: center; }
Vous devriez obtenir : plus aucun scroll horizontal indésirable, les cartes longues (titre de produit Sénégalais avec accents) se tronquent proprement avec text-overflow: ellipsis. Pour valider, ouvrez DevTools → onglet « Issues » : aucune alerte « Element overflows viewport » ne doit apparaître.
Étape 10 — Mettre en cache et déployer sur un hébergeur africain
Une fois la feuille de style finalisée, minifiez-la (Vite, esbuild ou simplement cssnano) et déposez-la sur un hébergeur proche du marché : LWS Africa, Hostinger région EU pour latence acceptable depuis Dakar, ou un Hetzner CX22 + Cloudflare gratuit pour servir les assets en edge à Lagos et Abidjan.
npx cssnano src/styles.css dist/styles.min.css
ls -lh dist/styles.min.css
Sortie attendue : un fichier dist/styles.min.css de 6 à 12 Ko gzippé pour une feuille typique de 200 lignes Grid+Flex. Au-dessus de 30 Ko, c’est le signe qu’il faut purger les classes inutiles (Tailwind content mal configuré, par exemple). Vous saurez que tout fonctionne quand : Lighthouse mobile (mode 4G ralenti) renvoie un score ≥90 sur Performance.