Cours HTML et CSS · Module 4: Flexbox

La propriété Gap - L'espacement moderne dans Flexbox

12 min de lecture
Dans cette leçon7

Bienvenue à nouveau ! Trois cartes sur une même rangée ont besoin d'espacements entre elles, mais pas contre les bords du conteneur. Pendant des années, nous avons obtenu cela avec des marges et des astuces à base de valeurs négatives. Les scribes égyptiens, eux aussi, veillaient aux espaces entre les hiéroglyphes, car la lisibilité en dépendait. Découvre la propriété gap, une façon moderne et propre de créer des espacements dans Flexbox.

Qu'est-ce que Gap ?

Gap est une propriété CSS moderne, largement prise en charge depuis 2021, qui crée des espacements entre les éléments flex sans utiliser margin.

Avant gap - l'ancienne méthode

Autrefois, chaque élément recevait une marge de tous les côtés, et le conteneur une marge négative, qui absorbait l'excédent au niveau des bords :

1/* Ancienne méthode - compliquée et source de problèmes */
2.container {
3  display: flex;
4  margin: -10px;  /* Marge négative sur le conteneur */
5}
6
7.item {
8  margin: 10px;  /* Marge sur chaque élément */
9}
10
11/* Problème : la marge est aussi sur les bords extérieurs ! */

Cela fonctionne, mais il faut surveiller deux endroits à la fois, car les marges des éléments se retrouvent aussi sur les bords extérieurs.

Avec gap - la nouvelle méthode

Avec gap, tout l'espacement est décrit par une seule déclaration sur le conteneur, et les éléments n'ont besoin d'aucune marge :

1/* Nouvelle méthode - propre et simple */
2.container {
3  display: flex;
4  gap: 20px;  /* Espacement uniquement ENTRE les éléments */
5}
6
7.item {
8  /* Pas besoin de margin ! */
9}
10
11/* Gap n'ajoute PAS d'espacement sur les bords extérieurs ! */

Gap n'ajoute de l'espacement qu'entre les éléments, jamais contre les bords du conteneur. C'est comme les espaces entre les hiéroglyphes gravés par un maître : précis, réguliers et sans aucun espace superflu.

La syntaxe de Gap

Gap accepte une ou deux valeurs, et au lieu du raccourci, tu peux utiliser deux propriétés séparées :

1/* Une dimension - même espacement horizontalement et verticalement */
2.container {
3  gap: 20px;
4}
5
6/* Deux dimensions - row-gap et column-gap */
7.container {
8  gap: 20px 40px;  /* 20px verticalement, 40px horizontalement */
9}
10
11/* Ou séparément */
12.container {
13  row-gap: 20px;
14  column-gap: 40px;
15}

Avec deux valeurs, la première est l'espacement entre les lignes, et la seconde l'espacement entre les colonnes, donc gap: 20px 40px signifie la même chose que row-gap: 20px et column-gap: 40px.

Gap dans les différentes directions de Flexbox

Gap fonctionne dans toutes les directions de l'axe principal, et avec le retour à la ligne, aussi entre les lignes :

1/* flex-direction: row (par défaut) */
2.container-row {
3  display: flex;
4  flex-direction: row;
5  gap: 20px;  /* Espacement entre les éléments horizontalement */
6}
7
8/* flex-direction: column */
9.container-column {
10  display: flex;
11  flex-direction: column;
12  gap: 20px;  /* Espacement entre les éléments verticalement */
13}
14
15/* flex-wrap: wrap */
16.container-wrap {
17  display: flex;
18  flex-wrap: wrap;
19  gap: 20px;  /* Espacement entre les lignes ET les colonnes */
20}

Dans une rangée, gap écarte les éléments horizontalement, dans une colonne verticalement, et avec flex-wrap: wrap, il sépare à la fois les éléments et les rangées successives.

Exemples pratiques

1. Grille de cartes

Le premier exemple est une grille de six cartes réparties sur trois colonnes :

1<div class="card-grid">
2  <div class="card">Card 1</div>
3  <div class="card">Card 2</div>
4  <div class="card">Card 3</div>
5  <div class="card">Card 4</div>
6  <div class="card">Card 5</div>
7  <div class="card">Card 6</div>
8</div>

Nous réduisons la largeur de chaque carte de sa part des espacements, car gap occupe lui aussi de la place dans la rangée :

1.card-grid {
2  display: flex;
3  flex-wrap: wrap;
4  gap: 20px;  /* Espacement parfait entre les cartes */
5}
6
7.card {
8  flex: 0 0 calc(33.333% - 14px);  /* 3 colonnes */
9  /* calc tient compte du gap : (40px de gap au total / 3 colonnes) ≈ 14px */
10  padding: 20px;
11  background: #3498db;
12  color: white;
13  border-radius: 8px;
14}
15
16@media (max-width: 768px) {
17  .card {
18    flex: 0 0 calc(50% - 10px);  /* 2 colonnes sur tablette */
19  }
20}
21
22@media (max-width: 480px) {
23  .card {
24    flex: 0 0 100%;  /* 1 colonne sur mobile */
25  }
26}

Trois cartes, cela fait deux espacements de 20 pixels, soit environ 13,3 pixels par carte, et le code arrondit ce nombre à 14. Ces calculs supposent box-sizing: border-box, sinon le padding des cartes s'ajoute à leur largeur et la troisième carte passe à une nouvelle rangée.

Les maths du gap pour plusieurs colonnes :

  • 3 colonnes avec un gap de 20px : calc(33.333% - 13.333px)
  • 4 colonnes avec un gap de 20px : calc(25% - 15px)
  • Formule : calc(100% / n_columns - gap * (n_columns - 1) / n_columns)

2. Groupe de boutons

Le deuxième exemple est un groupe de boutons poussés contre le bord droit :

1<div class="button-group">
2  <button class="btn">Cancel</button>
3  <button class="btn btn-primary">Save</button>
4  <button class="btn btn-danger">Delete</button>
5</div>

Le conteneur reçoit gap: 10px et justify-content: flex-end, tandis que les boutons eux-mêmes n'ont aucune marge :

1.button-group {
2  display: flex;
3  gap: 10px;  /* Espacement égal entre les boutons */
4  justify-content: flex-end;
5}
6
7.btn {
8  padding: 10px 20px;
9  border: 1px solid #ddd;
10  background: white;
11  cursor: pointer;
12  border-radius: 4px;
13}
14
15.btn-primary {
16  background: #3498db;
17  color: white;
18}
19
20.btn-danger {
21  background: #e74c3c;
22  color: white;
23}

Les boutons se tiennent à intervalles réguliers contre le bord droit, et quand tu en ajoutes un quatrième, l'espacement apparaît tout seul.

3. Mise en page de formulaire

Le troisième exemple est un formulaire dans lequel le prénom et le nom se trouvent sur une même ligne :

1<form class="form">
2  <div class="form-row">
3    <input type="text" placeholder="Prénom">
4    <input type="text" placeholder="Nom">
5  </div>
6  <input type="email" placeholder="Email">
7  <textarea placeholder="Message"></textarea>
8  <button type="submit">Send</button>
9</form>

Le formulaire est une colonne avec un espacement de 15 pixels, et la ligne du prénom et du nom est un conteneur flex séparé, avec le même gap :

1.form {
2  display: flex;
3  flex-direction: column;
4  gap: 15px;  /* Espacement entre les champs du formulaire */
5  max-width: 500px;
6}
7
8.form-row {
9  display: flex;
10  gap: 15px;  /* Espacement entre les champs d'une ligne */
11}
12
13.form input,
14.form textarea {
15  padding: 10px;
16  border: 1px solid #ddd;
17  border-radius: 4px;
18  font-family: inherit;
19}
20
21.form-row input {
22  flex: 1;  /* Largeur égale */
23}
24
25.form textarea {
26  min-height: 100px;
27  resize: vertical;
28}
29
30.form button {
31  padding: 12px;
32  background: #3498db;
33  color: white;
34  border: none;
35  border-radius: 4px;
36  cursor: pointer;
37  align-self: flex-start;
38}

Les champs de la ligne se partagent la largeur à parts égales grâce à flex: 1, et le bouton avec align-self: flex-start ne s'étire pas sur toute la largeur.

4. Barre de navigation

Le quatrième exemple est une barre de navigation avec un logo, un menu et des boutons :

1<nav class="navbar">
2  <div class="nav-brand">Logo</div>
3  <ul class="nav-menu">
4    <li><a href="#">Home</a></li>
5    <li><a href="#">About</a></li>
6    <li><a href="#">Services</a></li>
7    <li><a href="#">Contact</a></li>
8  </ul>
9  <div class="nav-actions">
10    <button>Login</button>
11    <button class="btn-primary">Sign Up</button>
12  </div>
13</nav>

Ici, gap travaille à trois niveaux : entre les sections de la barre, entre les liens et entre les boutons :

1.navbar {
2  display: flex;
3  align-items: center;
4  padding: 15px 30px;
5  background: #2c3e50;
6  gap: 30px;  /* Espacement entre les sections principales */
7}
8
9.nav-brand {
10  font-size: 1.5em;
11  font-weight: bold;
12  color: goldenrod;
13}
14
15.nav-menu {
16  display: flex;
17  list-style: none;
18  margin: 0;
19  padding: 0;
20  gap: 20px;  /* Espacement entre les liens */
21  flex: 1;  /* Occuper le milieu */
22}
23
24.nav-menu a {
25  color: white;
26  text-decoration: none;
27  transition: color 0.3s;
28}
29
30.nav-menu a:hover {
31  color: goldenrod;
32}
33
34.nav-actions {
35  display: flex;
36  gap: 10px;  /* Espacement entre les boutons */
37}
38
39.nav-actions button {
40  padding: 8px 16px;
41  border: 1px solid white;
42  background: transparent;
43  color: white;
44  cursor: pointer;
45  border-radius: 4px;
46}
47
48.nav-actions .btn-primary {
49  background: goldenrod;
50  border-color: goldenrod;
51  color: #2c3e50;
52}

Le menu, avec flex: 1, occupe le milieu. Quand la barre ne contient qu'un logo et un menu, justify-content: space-between sur le conteneur suffit : le logo va contre le bord gauche, le menu contre le bord droit, et align-items: center les aligne verticalement.

5. Mise en page de tableau de bord

Le cinquième exemple réunit tout : un panneau avec un menu latéral, un en-tête et des widgets :

1<div class="dashboard">
2  <aside class="sidebar">
3    <div class="sidebar-item">Dashboard</div>
4    <div class="sidebar-item">Analytics</div>
5    <div class="sidebar-item">Settings</div>
6  </aside>
7  <main class="dashboard-main">
8    <header class="dashboard-header">Header</header>
9    <div class="dashboard-content">
10      <div class="widget">Widget 1</div>
11      <div class="widget">Widget 2</div>
12      <div class="widget">Widget 3</div>
13      <div class="widget">Widget 4</div>
14    </div>
15  </main>
16</div>

Chaque niveau de la mise en page a son propre gap, et les widgets forment deux colonnes :

1.dashboard {
2  display: flex;
3  gap: 20px;  /* Espacement entre la sidebar et le main */
4  height: 100vh;
5  padding: 20px;
6}
7
8.sidebar {
9  display: flex;
10  flex-direction: column;
11  gap: 10px;  /* Espacement entre les items */
12  flex: 0 0 250px;
13  background: #34495e;
14  padding: 20px;
15  border-radius: 8px;
16}
17
18.sidebar-item {
19  padding: 12px;
20  background: #2c3e50;
21  color: white;
22  border-radius: 4px;
23  cursor: pointer;
24}
25
26.dashboard-main {
27  flex: 1;
28  display: flex;
29  flex-direction: column;
30  gap: 20px;  /* Espacement entre le header et le content */
31}
32
33.dashboard-header {
34  flex: 0 0 auto;
35  padding: 20px;
36  background: white;
37  border-radius: 8px;
38  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
39}
40
41.dashboard-content {
42  flex: 1;
43  display: flex;
44  flex-wrap: wrap;
45  gap: 20px;  /* Espacement entre les widgets */
46}
47
48.widget {
49  flex: 0 0 calc(50% - 10px);  /* 2 colonnes */
50  min-height: 200px;
51  padding: 20px;
52  background: white;
53  border-radius: 8px;
54  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
55}

Aucun élément n'a de marge, et pourtant tous les espacements sont égaux, car deux widgets avec calc(50% - 10px) se partagent un espacement en deux.

Gap vs Margin - quand utiliser quoi ?

Utilise Gap :

  • Pour les espacements entre les éléments d'un conteneur flex/grid
  • Pour des espacements réguliers, sans complications
  • Quand tu n'as pas besoin d'espacements extérieurs
  • Pour les mises en page responsive

Utilise Margin :

  • Pour les espacements extérieurs (par rapport au conteneur)
  • Pour des espacements asymétriques
  • Quand tu as besoin de margin: auto pour centrer
  • Quand tu dois prendre en charge de vieux navigateurs (avant 2021)

En pratique, les deux outils travaillent ensemble : gap et padding agissent à l'intérieur du conteneur, et margin à l'extérieur :

1/* Gap pour les espacements intérieurs */
2.container {
3  display: flex;
4  gap: 20px;
5  padding: 20px;  /* Espacement intérieur par rapport au bord */
6}
7
8/* Margin pour les espacements extérieurs */
9.container {
10  margin: 40px auto;  /* Centrer le conteneur */
11}
12
13/* Combinaison */
14.card {
15  /* Gap supprime le besoin de margin entre les items */
16  /* mais margin-top peut servir à un usage précis */
17  margin-top: auto;  /* Pousser vers le bas dans une colonne flex */
18}

margin: 40px auto centre toujours le conteneur, et margin-top: auto pousse un élément vers le bas d'une colonne flex. Mon conseil : confie toujours les espacements entre les éléments à gap, et garde margin pour les missions spéciales.

Gap responsive

Sur un petit écran, de grands espacements gaspillent de la place, il vaut donc la peine de réduire gap dans des media queries ou à l'aide de variables CSS :

1.container {
2  display: flex;
3  flex-wrap: wrap;
4  gap: 30px;
5}
6
7@media (max-width: 1024px) {
8  .container {
9    gap: 20px;  /* Gap plus petit sur tablette */
10  }
11}
12
13@media (max-width: 768px) {
14  .container {
15    gap: 15px;  /* Encore plus petit sur mobile */
16  }
17}
18
19/* Ou avec des variables CSS */
20:root {
21  --gap-large: 30px;
22  --gap-medium: 20px;
23  --gap-small: 15px;
24}
25
26.container {
27  gap: var(--gap-large);
28}
29
30@media (max-width: 768px) {
31  :root {
32    --gap-large: var(--gap-medium);
33  }
34}

La seconde version ne change que la valeur de la variable --gap-large, et chaque règle qui l'utilise s'adapte d'elle-même.

Prise en charge par les navigateurs

Gap dans Flexbox est pris en charge depuis :

  • Chrome 84+ (2020)
  • Firefox 63+ (2018)
  • Safari 14.1+ (2021)
  • Edge 84+ (2020)

Si tu dois prendre en charge des navigateurs plus anciens, commence par des marges et remplace-les là où gap est disponible :

1.container {
2  display: flex;
3  /* Solution de repli avec margin */
4  margin: -10px;
5}
6
7.item {
8  margin: 10px;
9}
10
11/* Modern browsers override */
12@supports (gap: 20px) {
13  .container {
14    gap: 20px;
15    margin: 0;
16  }
17
18  .item {
19    margin: 0;
20  }
21}

Attention au piège : @supports (gap: 20px) vérifie seulement si le navigateur connaît la propriété gap. Les anciennes versions de Chrome et de Safari la connaissaient déjà grâce à CSS Grid, alors qu'elles ne la prenaient pas encore en charge dans Flexbox, donc le test pouvait mentir. Aujourd'hui, ce genre de solution de repli est rarement nécessaire.

Récapitulatif

Gap est une façon moderne et propre de créer des espacements, qui fonctionne dans Flexbox comme dans Grid. Il n'ajoute de l'espacement qu'entre les éléments, accepte une ou deux valeurs, a une syntaxe plus simple que les marges et facilite le calcul des largeurs. Il fait merveille dans les grilles de cartes, les groupes de boutons, les formulaires, les barres de navigation et les tableaux de bord. Dans la leçon suivante, nous nous occuperons de l'accessibilité.

Dans l'éditeur ci-dessous, tu compareras les deux approches : le premier exemple gère les espacements avec des marges, le deuxième utilise gap: 10px, et le troisième définit séparément row-gap et column-gap.

Code de cette leçon : index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Flexbox Gap Property</title>
6    <link rel="stylesheet" href="style.css">
7</head>
8<body>
9    <h1>Gap en Flexbox</h1>
10
11    <h2>Sans gap (ancienne méthode avec margin)</h2>
12    <div class="container-old">
13        <div class="box">A</div>
14        <div class="box">B</div>
15        <div class="box">C</div>
16        <div class="box">D</div>
17    </div>
18
19    <h2>Avec gap (méthode moderne)</h2>
20    <div class="container-gap">
21        <div class="box">A</div>
22        <div class="box">B</div>
23        <div class="box">C</div>
24        <div class="box">D</div>
25    </div>
26
27    <h2>Row-gap et column-gap séparément</h2>
28    <div class="container-mixed">
29        <div class="box">1</div>
30        <div class="box">2</div>
31        <div class="box">3</div>
32        <div class="box">4</div>
33        <div class="box">5</div>
34        <div class="box">6</div>
35    </div>
36</body>
37</html>

Retiens : gap, ce sont les espacements parfaits entre les hiéroglyphes d'un papyrus égyptien, précis et réguliers, et en plus définis en une seule déclaration, sans complications.

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. À quoi sert la propriété gap dans un conteneur Flexbox ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée une barre de navigation avec un logo à gauche et 4 liens de menu à droite, en utilisant Flexbox avec justify-content: space-between et align-items: center.

Articles utiles