Cours HTML et CSS · Module 4: Flexbox
Flex-grow, Flex-shrink, Flex-basis - Contrôle précis de la taille
Dans cette leçon7
Bienvenue à nouveau à la Bibliothèque d'Alexandrie ! Sur une même étagère reposent trois rouleaux : le premier a toujours besoin de la même place, le deuxième peut occuper tout le reste, et le troisième cède du terrain quand l'espace se resserre, exactement comme le menu, le contenu et le panneau latéral d'une page. Ce sont flex-basis, flex-grow et flex-shrink qui en décident.
Flex-basis - la taille initiale d'un élément
flex-basis définit la taille initiale d'un élément AVANT la répartition de l'espace libre. Elle accepte des pixels, des pourcentages, zéro ou auto :
1.item {
2 flex-basis: 200px; /* Taille initiale 200px */
3}
4
5.item {
6 flex-basis: 0; /* Ignorer la taille du contenu, partir de 0 */
7}
8
9.item {
10 flex-basis: auto; /* Utiliser la taille du contenu (par défaut) */
11}
12
13.item {
14 flex-basis: 50%; /* 50% du conteneur */
15}Zéro demande d'ignorer la taille du contenu. La valeur par défaut auto prend la largeur de l'élément, et si celle-ci n'est pas définie, la taille du contenu. En quoi flex-basis diffère-t-elle donc de width ?
1/* En dehors de flexbox, width est rigide */
2.item {
3 width: 200px; /* En dehors de flexbox, toujours 200px */
4}
5
6/* Flex-basis est une suggestion */
7.item {
8 flex-basis: 200px; /* Environ 200px, mais peut grandir/rétrécir */
9}En dehors de flexbox, width: 200px, c'est toujours 200 pixels. Dans un conteneur flex, les deux valeurs sont un point de départ : avec flex-basis: auto, le navigateur prend width, et si tu définis les deux, c'est flex-basis qui l'emporte. C'est comme un bloc de pierre pas encore sculpté, qu'on peut encore agrandir ou réduire.
Flex-grow - la croissance d'un élément
flex-grow détermine dans quelle mesure un élément peut grandir par rapport aux autres lorsqu'il reste de l'espace libre :
1.container {
2 display: flex;
3 width: 600px;
4}
5
6.item-1 {
7 flex-grow: 1; /* Prendra 1 part de l'espace libre */
8 flex-basis: 100px;
9}
10
11.item-2 {
12 flex-grow: 2; /* Prendra 2 parts de l'espace libre */
13 flex-basis: 100px;
14}
15
16.item-3 {
17 flex-grow: 1; /* Prendra 1 part de l'espace libre */
18 flex-basis: 100px;
19}
20
21/* Espace libre : 600px - 300px = 300px
22 Somme des flex-grow : 1 + 2 + 1 = 4
23
24 item-1: 100px + (300px × 1/4) = 175px
25 item-2: 100px + (300px × 2/4) = 250px
26 item-3: 100px + (300px × 1/4) = 175px
27*/Le navigateur divise les 300 pixels libres en quatre parts, car c'est la somme des flex-grow. Attention : flex-grow: 2 ne rend pas l'élément deux fois plus grand, il lui donne une part d'espace libre deux fois plus grande. La valeur par défaut flex-grow: 0 signifie aucune croissance, 1 une croissance proportionnelle, et 2 ou 3 une part deux ou trois fois plus grande. En général, seul le contenu situé entre les panneaux grandit :
1.layout {
2 display: flex;
3}
4
5.sidebar {
6 flex-grow: 0; /* La sidebar ne grandit PAS */
7 flex-basis: 250px; /* Taille fixe de 250px */
8}
9
10.main-content {
11 flex-grow: 1; /* Le contenu principal prend tout l'espace restant */
12}
13
14.aside {
15 flex-grow: 0; /* L'aside ne grandit PAS */
16 flex-basis: 200px;
17}Le menu et le panneau gardent 250 et 200 pixels, et le contenu, avec flex-grow: 1, prend tout le reste.
Flex-shrink - le rétrécissement d'un élément
flex-shrink fonctionne dans l'autre sens : elle détermine dans quelle mesure un élément peut rétrécir quand la place manque. Sa valeur par défaut est 1 :
1.item {
2 flex-shrink: 1; /* L'élément peut rétrécir (par défaut) */
3}
4
5.item-important {
6 flex-shrink: 0; /* L'élément ne rétrécit PAS */
7}
8
9.item-flexible {
10 flex-shrink: 3; /* L'élément rétrécit 3x plus vite que les autres */
11}Zéro désactive le rétrécissement, et un nombre plus grand signifie une plus grande part dans la place cédée. Vérifions-le dans un conteneur où il manque 200 pixels :
1.container {
2 display: flex;
3 width: 400px;
4}
5
6.item-1 {
7 flex-basis: 200px;
8 flex-shrink: 1; /* Rétrécit normalement */
9}
10
11.item-2 {
12 flex-basis: 200px;
13 flex-shrink: 2; /* Rétrécit 2x plus vite */
14}
15
16.item-3 {
17 flex-basis: 200px;
18 flex-shrink: 0; /* Ne rétrécit PAS */
19}
20
21/* Total : 600px, mais le conteneur ne fait que 400px
22 Manquant : 200px
23
24 item-3 restera à 200px (flex-shrink: 0)
25 item-1 et item-2 se partageront le rétrécissement proportionnellement
26*/Le troisième élément reste à 200 pixels, et les 200 pixels manquants sont cédés par les deux premiers dans une proportion de 1 à 2 : le premier rétrécit à environ 133 pixels, le deuxième à environ 67. Pour le rétrécissement, flex-basis compte aussi, donc les éléments plus grands cèdent davantage. Le plus souvent, flex-shrink protège les éléments qui ne doivent pas être écrasés, comme un logo :
1.header-logo {
2 flex-shrink: 0; /* Le logo ne rétrécit JAMAIS */
3 width: 150px;
4}
5
6.header-nav {
7 flex-shrink: 1; /* La navigation peut rétrécir */
8}
9
10.header-search {
11 flex-shrink: 2; /* La recherche rétrécit le plus vite */
12}Le logo mesure toujours 150 pixels, et quand l'espace se resserre, la recherche, avec flex-shrink: 2, cède sa place plus volontiers que la navigation.
Le raccourci flex - réunir les trois
Tu connais depuis la leçon précédente le raccourci flex, qui réunit les trois valeurs dans l'ordre grow, shrink, basis :
1/* flex: grow shrink basis */
2.item {
3 flex: 1 1 200px;
4 /* flex-grow: 1, flex-shrink: 1, flex-basis: 200px */
5}De la même façon, flex: 1 0 200px correspond à flex-grow: 1, flex-shrink: 0 et flex-basis: 200px.
Les valeurs de flex les plus courantes :
Au quotidien, quelques formes toutes faites suffisent, et elles valent la peine d'être connues par cœur :
1/* flex: 1 - élément flexible */
2.item {
3 flex: 1;
4 /* Équivalent : flex: 1 1 0 */
5 /* Grandir, rétrécir, partir de 0 */
6}
7
8/* flex: auto - taille naturelle avec flexibilité */
9.item {
10 flex: auto;
11 /* Équivalent : flex: 1 1 auto */
12 /* Grandir, rétrécir, partir de la taille du contenu */
13}
14
15/* flex: none - taille rigide */
16.item {
17 flex: none;
18 /* Équivalent : flex: 0 0 auto */
19 /* NE PAS grandir, NE PAS rétrécir */
20}
21
22/* flex: 0 0 200px - absolument rigide */
23.item {
24 flex: 0 0 200px;
25 /* Toujours 200px, sans grandir/rétrécir */
26}
27
28/* flex: 2 - grandir 2x plus vite */
29.item {
30 flex: 2;
31 /* Équivalent : flex: 2 1 0 */
32}flex: 1 part de zéro, donc plusieurs éléments de ce type se partagent la place à parts égales, tandis que flex: auto part de la taille du contenu, donc un texte plus long obtiendra une colonne plus large. Mon conseil : pour des colonnes égales, choisis flex: 1.
Exemples pratiques
1. Mise en page de tableau de bord - 3 colonnes
La première mise en page est un panneau d'administration avec un menu, un contenu et des widgets :
1<div class="dashboard">
2 <aside class="sidebar">Sidebar (fixe)</aside>
3 <main class="main-content">Main (flexible)</main>
4 <aside class="widgets">Widgets (fixe)</aside>
5</div>Le menu reçoit un flex: 0 0 250px rigide, le contenu flex: 1, et le panneau flex: 0 1 300px, c'est-à-dire qu'il préfère 300 pixels, mais peut céder de la place :
1.dashboard {
2 display: flex;
3 gap: 20px;
4 height: 100vh;
5}
6
7.sidebar {
8 flex: 0 0 250px; /* Rigide : 250px */
9 background: #34495e;
10}
11
12.main-content {
13 flex: 1; /* Prend tout l'espace restant */
14 background: white;
15 overflow-y: auto;
16}
17
18.widgets {
19 flex: 0 1 300px; /* Préféré : 300px, peut rétrécir */
20 background: #ecf0f1;
21}
22
23/* Sur les petits écrans */
24@media (max-width: 768px) {
25 .dashboard {
26 flex-direction: column;
27 }
28
29 .sidebar,
30 .widgets {
31 flex: 0 0 auto; /* Taille automatique */
32 }
33}Sur un téléphone, la media query place les colonnes les unes sous les autres et rend aux panneaux leur taille naturelle grâce à flex: 0 0 auto.
2. En-tête responsive
Le deuxième exemple est un en-tête avec un logo, une navigation, une recherche et un compte utilisateur :
1<header class="header">
2 <div class="logo">Logo</div>
3 <nav class="nav">Navigation</nav>
4 <div class="search">Recherche</div>
5 <div class="user">User</div>
6</header>Remarque min-width: 0 sur la navigation et min-width: 150px sur la recherche, sur lesquels nous reviendrons dans la partie consacrée au débogage :
1.header {
2 display: flex;
3 gap: 20px;
4 padding: 10px 20px;
5 background: #2c3e50;
6 align-items: center;
7}
8
9.logo {
10 flex: 0 0 150px; /* Toujours 150px */
11}
12
13.nav {
14 flex: 1 1 auto; /* Prend l'espace disponible */
15 min-width: 0; /* Important pour le rétrécissement */
16}
17
18.search {
19 flex: 0 1 300px; /* Préfère 300px, peut rétrécir */
20 min-width: 150px; /* Minimum 150px */
21}
22
23.user {
24 flex: 0 0 100px; /* Toujours 100px */
25}La navigation prend l'espace libre, tandis que la recherche préfère 300 pixels, mais ne descendra pas en dessous de 150.
3. Grille de cartes de tailles différentes
Le troisième exemple est une grille de cartes de trois tailles différentes :
1<div class="card-grid">
2 <div class="card small">Small</div>
3 <div class="card medium">Medium</div>
4 <div class="card large">Large</div>
5 <div class="card small">Small</div>
6</div>Le conteneur fait passer les cartes à la ligne grâce à flex-wrap: wrap, autrement dit le flex-flow: row wrap de la leçon précédente. Les petites cartes prennent un quart de la largeur moins une part de l'espacement, les moyennes la moitié, et les grandes toute la rangée :
1.card-grid {
2 display: flex;
3 flex-wrap: wrap;
4 gap: 20px;
5}
6
7.card {
8 height: 200px;
9 background: #3498db;
10 color: white;
11 display: flex;
12 align-items: center;
13 justify-content: center;
14}
15
16.card.small {
17 flex: 0 0 calc(25% - 15px); /* 1/4 de la largeur moins le gap */
18}
19
20.card.medium {
21 flex: 0 0 calc(50% - 10px); /* 1/2 de la largeur moins le gap */
22}
23
24.card.large {
25 flex: 0 0 100%; /* Pleine largeur */
26}
27
28@media (max-width: 768px) {
29 .card.small,
30 .card.medium {
31 flex: 0 0 100%; /* Pleine largeur sur mobile */
32 }
33}Quatre petites cartes rempliraient la rangée au pixel près, car quatre fois calc(25% - 15px) plus trois espacements de 20 pixels font 100%.
Déboguer Flexbox
Problème 1 : width bloque-t-il la croissance ?
Beaucoup de débutants pensent que width, associé à flex-grow, bloque la croissance. Voici un tel code et deux recettes populaires :
1/* Problème */
2.item {
3 flex-grow: 1;
4 width: 200px; /* Ce n'est qu'un point de départ */
5}
6
7/* Solution */
8.item {
9 flex: 1; /* flex remplace automatiquement width */
10 /* ou */
11 flex-grow: 1;
12 min-width: 200px; /* Utilise min-width au lieu de width */
13}C'est un mythe : dans un conteneur de 600 pixels de large, deux éléments de ce type mesurent 300 pixels chacun, car width n'est qu'un point de départ. Le souci apparaît quand les voisins ont des largeurs différentes, car chacun part alors d'un point différent, et flex: 1 égalise ce départ. Si un élément ne grandit vraiment pas, vérifie flex-grow, max-width et si le parent a bien display: flex.
Problème 2 : l'élément ne rétrécit pas
Ce problème-là est bien réel : un élément avec flex-shrink: 1 garde obstinément sa largeur :
1/* Problème */
2.item {
3 flex-shrink: 1;
4 min-width: 300px; /* min-width empêche le rétrécissement ! */
5}
6
7/* Solution */
8.item {
9 flex-shrink: 1;
10 min-width: 0; /* Autorise le rétrécissement */
11}Le coupable, c'est min-width. Les éléments flex ont par défaut min-width: auto, ils ne rétrécissent donc pas en dessous de leur plus long contenu insécable, par exemple une adresse URL.
Problème 3 : le texte déborde du conteneur
De cette valeur par défaut découle un troisième problème, celui d'un long texte qui pousse l'élément hors du conteneur :
1/* Problème */
2.item {
3 flex: 1;
4 /* Un texte long peut pousser l'élément hors du conteneur */
5}
6
7/* Solution */
8.item {
9 flex: 1;
10 min-width: 0; /* Crucial ! */
11 overflow: hidden;
12 text-overflow: ellipsis;
13 white-space: nowrap;
14}min-width: 0 permet à l'élément de rétrécir, overflow: hidden coupe ce qui dépasse, et text-overflow: ellipsis ajoute des points de suspension à un texte maintenu sur une seule ligne.
Récapitulatif
flex-basis est l'équivalent flexible de width, flex-grow, dont la valeur par défaut est 0, décide de la croissance, et flex-shrink, dont la valeur par défaut est 1, du rétrécissement. Le raccourci flex réunit les trois. Dans la leçon suivante, tu construiras avec ces briques toute une grille de colonnes.
Dans l'éditeur ci-dessous t'attend une démonstration des espacements, sur laquelle nous reviendrons avec gap. Ajoute la règle .flex-item:first-child { flex-grow: 1; } et regarde le premier élément prendre l'espace libre à ses voisins.
Code de cette leçon : index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Flexbox - Gap</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10 <div class="container">
11 <h1>↔Gap - Espacement entre les éléments</h1>
12 <p class="subtitle">Façon moderne de créer de l'espacement en flexbox</p>
13
14 <section class="demo-section">
15 <h2>Sans gap</h2>
16 <div class="flex-container no-gap">
17 <div class="flex-item">1</div>
18 <div class="flex-item">2</div>
19 <div class="flex-item">3</div>
20 <div class="flex-item">4</div>
21 </div>
22 <p class="description">Éléments sans espacement</p>
23 </section>
24
25 <section class="demo-section">
26 <h2>gap: 10px</h2>
27 <div class="flex-container gap-10">
28 <div class="flex-item">1</div>
29 <div class="flex-item">2</div>
30 <div class="flex-item">3</div>
31 <div class="flex-item">4</div>
32 </div>
33 <p class="description">Petit espacement entre tous les éléments</p>
34 </section>
35
36 <section class="demo-section">
37 <h2>gap: 30px</h2>
38 <div class="flex-container gap-30">
39 <div class="flex-item">1</div>
40 <div class="flex-item">2</div>
41 <div class="flex-item">3</div>
42 <div class="flex-item">4</div>
43 </div>
44 <p class="description">Grand espacement entre les éléments</p>
45 </section>
46
47 <section class="demo-section">
48 <h2>row-gap et column-gap séparément</h2>
49 <div class="flex-container custom-gap">
50 <div class="flex-item">1</div>
51 <div class="flex-item">2</div>
52 <div class="flex-item">3</div>
53 <div class="flex-item">4</div>
54 <div class="flex-item">5</div>
55 <div class="flex-item">6</div>
56 </div>
57 <p class="description">row-gap: 40px, column-gap: 10px</p>
58 </section>
59
60 <section class="demo-section practice">
61 <h2>Exercice : plateau de Senet égyptien</h2>
62 <p class="practice-description">Le jeu de Senet - le plus ancien jeu de plateau d'Égypte</p>
63
64 <div class="board-container">
65 <div class="senet-board">
66 <div class="square">●</div>
67 <div class="square">●</div>
68 <div class="square empty"></div>
69 <div class="square">●</div>
70 <div class="square">●</div>
71 <div class="square">●</div>
72 <div class="square empty"></div>
73 <div class="square">●</div>
74 <div class="square empty"></div>
75 <div class="square">●</div>
76 <div class="square">●</div>
77 <div class="square empty"></div>
78 <div class="square">●</div>
79 <div class="square empty"></div>
80 <div class="square">●</div>
81 <div class="square">●</div>
82 <div class="square empty"></div>
83 <div class="square">●</div>
84 <div class="square">●</div>
85 <div class="square empty"></div>
86 <div class="square">●</div>
87 <div class="square empty"></div>
88 <div class="square">●</div>
89 <div class="square">●</div>
90 <div class="square empty"></div>
91 <div class="square">●</div>
92 <div class="square">●</div>
93 <div class="square empty"></div>
94 <div class="square">●</div>
95 <div class="square">●</div>
96 </div>
97 </div>
98
99 <div class="game-info">
100 <h3>ℹÀ propos du jeu de Senet :</h3>
101 <ul>
102 <li>Le plus ancien jeu de plateau connu (env. 3100 av. J.-C.)</li>
103 <li>Jeu pour 2 joueurs</li>
104 <li>Plateau de 3x10 cases</li>
105 <li>Jeu favori des pharaons</li>
106 <li>Retrouvé dans les tombes égyptiennes</li>
107 </ul>
108 </div>
109 </section>
110 </div>
111</body>
112</html>Retiens : flex-grow, flex-shrink et flex-basis sont les ordres du pharaon aux bâtisseurs de pyramides, qui indiquent quels blocs doivent grandir, lesquels doivent rapetisser et lesquels doivent rester intacts.
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. Que fait la propriété flex-grow ?
2. À quel ensemble de valeurs correspond la propriété raccourcie flex: 1 0 200px ?
Tâches pratiques dans le jeu
- Tri vertical
Range les valeurs de flex-grow, de la plus faible à la plus forte croissance :
- Tri horizontal
Compose le raccourci flex-flow qui définit le sens horizontal avec retour à la ligne des éléments :
- Clique dans l'ordre
Range les éléments pour créer une déclaration flex-basis valide :
- Tri horizontal
Range l'ordre des valeurs dans la propriété raccourcie flex :