Cours HTML et CSS · Module 4: Flexbox

Order et Align-self - Contrôle individuel des éléments

11 min de lecture
Dans cette leçon5

Bienvenue à nouveau à la Bibliothèque d'Alexandrie ! Sur un téléphone, le contenu devrait apparaître avant le menu latéral, alors que le HTML doit rester intact. Les bibliothécaires connaissaient bien ce problème : pour la visite du pharaon, le papyrus le plus précieux passait à l'avant de l'étagère, tandis que le catalogue restait inchangé. Dans Flexbox, ce genre d'exceptions se règle avec order et align-self.

Order - changer l'ordre visuel

La propriété order change l'ordre d'affichage sans modifier le HTML. Elle accepte un nombre entier, et au départ, tous les éléments ont la même valeur :

1.item {
2  order: 0;  /* Valeur par défaut pour tous les éléments */
3}
4
5/* Valeur plus basse = plus tôt */
6/* Valeur plus haute = plus tard */

Les éléments sont triés par ordre croissant. En cas d'égalité, c'est l'ordre du HTML qui décide, et les valeurs négatives, comme order: -1, sont autorisées.

Exemple de base

Voici quatre boîtes que le HTML énumère l'une après l'autre :

1<div class="container">
2  <div class="item-1">1</div>
3  <div class="item-2">2</div>
4  <div class="item-3">3</div>
5  <div class="item-4">4</div>
6</div>

Maintenant, dans le CSS, la boîte 3 reçoit une valeur négative, la boîte 1 une valeur positive, et les autres restent à la valeur par défaut, zéro :

1.container {
2  display: flex;
3}
4
5/* Par défaut : 1, 2, 3, 4 */
6
7.item-3 {
8  order: -1;  /* Sera en premier : 3, 1, 2, 4 */
9}
10
11.item-1 {
12  order: 1;  /* Sera en dernier : 3, 2, 4, 1 */
13}
14
15/* Résultat : 3, 2, 4, 1 */

La boîte 3 passe en tête, la boîte 1 à la fin, et les boîtes 2 et 4 gardent l'ordre du HTML, qui, lui, n'a pas changé du tout.

Exemple pratique - mise en page responsive

La force de order se révèle dans les mises en page qui changent en même temps que l'écran :

1<div class="layout">
2  <header class="header">Header</header>
3  <nav class="sidebar">Sidebar</nav>
4  <main class="content">Content</main>
5  <aside class="ads">Ads</aside>
6  <footer class="footer">Footer</footer>
7</div>

Le CSS utilise des outils des leçons suivantes : flex-wrap: wrap fait passer les sections sur une nouvelle ligne, flex: 0 0 100% occupe toute la largeur, flex: 1 prend le reste de la place, et le bloc @media (max-width: 768px) ne s'applique qu'aux écrans d'au plus 768 pixels :

1.layout {
2  display: flex;
3  flex-wrap: wrap;
4}
5
6/* Desktop - ordre par défaut */
7.header { order: 1; flex: 0 0 100%; }
8.sidebar { order: 2; flex: 0 0 25%; }
9.content { order: 3; flex: 1; }
10.ads { order: 4; flex: 0 0 20%; }
11.footer { order: 5; flex: 0 0 100%; }
12
13/* Mobile - changer l'ordre */
14@media (max-width: 768px) {
15  .header { order: 1; }
16  .content { order: 2; }  /* Content avant la sidebar ! */
17  .sidebar { order: 3; }
18  .ads { order: 4; }
19  .footer { order: 5; }
20
21  /* Tous en pleine largeur */
22  .header, .sidebar, .content, .ads, .footer {
23    flex: 0 0 100%;
24  }
25}

Sur un téléphone, le contenu avec order: 2 passe devant le menu latéral, et le HTML ne bouge pas, comme une pyramide dans laquelle le pharaon n'a changé que le parcours de visite. Mon conseil : ne donne order qu'aux sections qui doivent vraiment se déplacer, et laisse les autres à zéro.

Exemple pratique - tri de produits

Dans une boutique, les produits mis en avant doivent se placer en tête de la liste :

1<div class="products">
2  <div class="product" data-priority="normal">Produit A</div>
3  <div class="product featured" data-priority="high">Produit B</div>
4  <div class="product" data-priority="normal">Produit C</div>
5  <div class="product sale" data-priority="medium">Produit D</div>
6</div>

Ici, le CSS réagit aux classes featured et sale, tandis que data-priority n'est qu'une description. gap: 20px crée les espacements, et calc(33.333% - 14px) correspond à un tiers de la largeur moins une part de ces espacements :

1.products {
2  display: flex;
3  flex-wrap: wrap;
4  gap: 20px;
5}
6
7.product {
8  flex: 0 0 calc(33.333% - 14px);
9  order: 3;  /* Produits normaux à la fin */
10}
11
12.product.featured {
13  order: 1;  /* Mis en avant au début */
14  border: 3px solid goldenrod;
15}
16
17.product.sale {
18  order: 2;  /* Soldes au milieu */
19  background: #e74c3c;
20  color: white;
21}
22
23/* Résultat : Featured → Sale → Normal → Normal */

Le produit B, mis en avant, passe en premier, le produit D, en solde, en deuxième, et A et C ferment la rangée dans l'ordre du HTML.

Remarques sur l'accessibilité

Il y a un piège : order ne change que l'ordre visuel, et non le DOM, que suivent le clavier et les lecteurs d'écran. Prenons trois onglets :

1<div class="tabs">
2  <button>Tab 1</button>
3  <button>Tab 2</button>
4  <button>Tab 3</button>
5</div>

Dans le HTML, le bouton Tab 1 se trouve au début. Déplaçons-le visuellement tout au bout de la barre :

1.tabs button:first-child {
2  order: 3;  /* Visuellement dernier */
3}
4
5/* Problème : la navigation au clavier (Tab) conservera l'ordre d'origine ! */

À l'écran, Tab 1 est le dernier, mais le clavier et le lecteur d'écran l'atteindront toujours en premier. La spécification de Flexbox le dit clairement : order sert aux changements visuels, et non logiques, donc quand l'ordre modifie le sens du contenu, réorganise le HTML et vérifie la mise en page uniquement au clavier.

Align-self - l'alignement individuel

align-self agit perpendiculairement à l'axe principal : cette propriété remplace, pour un seul élément, la valeur align-items du conteneur.

Les valeurs de align-self

Elle accepte les valeurs que tu connais déjà grâce à align-items, ainsi que auto :

1.item {
2  align-self: auto;          /* Hérite de align-items (par défaut) */
3  align-self: flex-start;    /* Au début de l'axe secondaire */
4  align-self: flex-end;      /* À la fin de l'axe secondaire */
5  align-self: center;        /* Centré */
6  align-self: baseline;      /* Aligné sur la ligne de base du texte */
7  align-self: stretch;       /* Étiré (si pas de height) */
8}

La valeur par défaut auto reprend la valeur align-items du parent, et stretch n'étire l'élément que s'il n'a pas de hauteur fixée.

Exemple de base

L'élément du milieu, parmi les trois, a reçu une classe supplémentaire special :

1<div class="container">
2  <div class="item">Item 1</div>
3  <div class="item special">Item 2 (Special)</div>
4  <div class="item">Item 3</div>
5</div>

Le conteneur centre tous les éléments avec align-items: center, puis nous faisons une seule exception pour l'élément mis en avant :

1.container {
2  display: flex;
3  align-items: center;  /* Tous centrés */
4  height: 300px;
5  border: 2px solid #ddd;
6}
7
8.item {
9  padding: 20px;
10  background: #3498db;
11  color: white;
12}
13
14/* Un élément aligné différemment */
15.item.special {
16  align-self: flex-start;  /* Celui-ci sera en haut */
17  background: goldenrod;
18}

Item 2 se colle au bord supérieur, tandis que les autres restent au milieu, car la règle du conteneur s'applique toujours.

Exemples pratiques

1. Carte avec bouton en bas

Dans des cartes dont le contenu n'a pas la même longueur, les boutons doivent être alignés en bas :

1<div class="cards">
2  <div class="card">
3    <h3>Produit 1</h3>
4    <p>Brève description</p>
5    <button class="btn">Acheter maintenant</button>
6  </div>
7  <div class="card">
8    <h3>Produit 2</h3>
9    <p>Une très longue description qui prend beaucoup plus de place...</p>
10    <button class="btn">Acheter maintenant</button>
11  </div>
12</div>

Chaque carte devient un conteneur flex en colonne, et le bouton reçoit align-self: stretch et margin-top: auto, c'est-à-dire une marge qui absorbe tout l'espace libre au-dessus de lui :

1.cards {
2  display: flex;
3  gap: 20px;
4}
5
6.card {
7  flex: 1;
8  display: flex;
9  flex-direction: column;
10  padding: 20px;
11  border: 1px solid #ddd;
12}
13
14.card h3,
15.card p {
16  flex: 0;
17}
18
19.card .btn {
20  align-self: stretch;  /* Bouton en pleine largeur */
21  margin-top: auto;  /* Pousser vers le bas */
22}

Dans une colonne, l'axe secondaire est horizontal, donc le bouton s'étire sur toute la largeur de la carte, et la marge le pousse vers le bas.

2. Avatar dans un message de chat

Dans une bulle de chat, la photo de l'auteur se trouve à côté du message et de l'heure d'envoi :

1<div class="message">
2  <img src="avatar.jpg" alt="User" class="avatar">
3  <div class="message-content">
4    <h4>User Name</h4>
5    <p>Voici un message qui peut être long...</p>
6    <span class="timestamp">10:30</span>
7  </div>
8</div>

Le conteneur place tout en haut, l'avatar reçoit l'exception align-self: center, et flex-shrink: 0 l'empêche d'être écrasé :

1.message {
2  display: flex;
3  gap: 15px;
4  align-items: flex-start;  /* Tout en haut */
5  padding: 15px;
6}
7
8.avatar {
9  width: 50px;
10  height: 50px;
11  border-radius: 50%;
12  flex-shrink: 0;
13  align-self: center;  /* Avatar centré verticalement */
14}
15
16.message-content {
17  flex: 1;
18}
19
20.timestamp {
21  align-self: flex-end;  /* Horodatage en bas */
22  font-size: 0.8em;
23  color: #777;
24}

L'avatar se place au milieu, mais attention au piège : align-self ne fonctionne que sur les enfants d'un conteneur flex, et .timestamp se trouve dans .message-content, qui n'a pas de display: flex, donc l'heure ne bougera pas. Ajoute-y display: flex et flex-direction: column, et flex-end déplacera l'heure vers le bord droit.

3. Barre d'outils avec icônes

Dans une barre d'outils, une des icônes est plus grande que les autres :

1<div class="toolbar">
2  <button class="tool">Icon 1</button>
3  <button class="tool">Icon 2</button>
4  <button class="tool large">Big Icon</button>
5  <button class="tool">Icon 3</button>
6</div>

La barre centre les icônes, et la grande reçoit l'exception align-self: flex-start ainsi qu'un fond doré :

1.toolbar {
2  display: flex;
3  gap: 10px;
4  padding: 10px;
5  background: #34495e;
6  align-items: center;  /* Tous centrés */
7}
8
9.tool {
10  width: 40px;
11  height: 40px;
12  background: #3498db;
13  border: none;
14  color: white;
15  cursor: pointer;
16}
17
18.tool.large {
19  width: 60px;
20  height: 60px;
21  align-self: flex-start;  /* Aligné en haut */
22  background: goldenrod;
23}

La grande icône est la plus haute, donc flex-start ressemble ici à center, tant que la barre n'a pas reçu height: 80px.

Order + Align-self - la combinaison

Dans une section hero, les deux propriétés travaillent ensemble :

1<div class="hero">
2  <div class="hero-image">Image</div>
3  <div class="hero-content">Content</div>
4</div>

L'image avec order: 2 va à droite, le contenu avec order: 1 et align-self: flex-start à gauche, et sur un téléphone, l'ordre s'inverse :

1.hero {
2  display: flex;
3  align-items: center;
4  min-height: 500px;
5  gap: 40px;
6}
7
8.hero-image {
9  flex: 0 0 50%;
10  order: 2;  /* Image à droite */
11}
12
13.hero-content {
14  flex: 1;
15  order: 1;  /* Content à gauche */
16  align-self: flex-start;  /* Content en haut */
17}
18
19/* Sur mobile */
20@media (max-width: 768px) {
21  .hero {
22    flex-direction: column;
23  }
24
25  .hero-image {
26    order: 1;  /* Image en haut */
27    flex: 0 0 auto;
28  }
29
30  .hero-content {
31    order: 2;  /* Content en bas */
32    align-self: stretch;  /* Pleine largeur */
33  }
34}

Sur un téléphone, l'image passe en haut, et le contenu en dessous s'étire sur toute la largeur, car dans une colonne, stretch agit horizontalement.

Schémas pratiques

1. Élément mis en avant en premier

L'élément mis en avant ouvre toujours la galerie et occupe toute une rangée :

1.grid {
2  display: flex;
3  flex-wrap: wrap;
4  gap: 20px;
5}
6
7.grid-item {
8  flex: 0 0 calc(33.333% - 14px);
9  order: 2;
10}
11
12.grid-item.featured {
13  flex: 0 0 100%;
14  order: 1;  /* Toujours en premier */
15  align-self: stretch;
16  background: goldenrod;
17}

Il a order: 1, et les autres order: 2, donc sa place dans le HTML n'a aucune importance.

2. Pied de page collé en bas d'une carte

Le pied de page d'une carte doit rester collé en bas :

1.card {
2  display: flex;
3  flex-direction: column;
4  height: 100%;
5}
6
7.card-header {
8  flex: 0 0 auto;
9}
10
11.card-body {
12  flex: 1;
13}
14
15.card-footer {
16  flex: 0 0 auto;
17  align-self: stretch;
18  margin-top: auto;  /* Toujours en bas */
19}

La partie centrale, avec flex: 1, prend l'espace libre, et margin-top: auto colle le pied de page en bas.

3. Formulaire responsive

Le bouton d'envoi ferme toujours le formulaire :

1.form {
2  display: flex;
3  flex-wrap: wrap;
4  gap: 15px;
5}
6
7.form-field {
8  flex: 0 0 calc(50% - 7.5px);
9}
10
11.form-field.full {
12  flex: 0 0 100%;
13}
14
15.form-submit {
16  flex: 0 0 auto;
17  order: 999;  /* Toujours à la fin */
18  align-self: flex-end;
19  margin-top: 10px;
20}
21
22@media (max-width: 768px) {
23  .form-field {
24    flex: 0 0 100%;
25  }
26
27  .form-submit {
28    flex: 0 0 100%;  /* Pleine largeur sur mobile */
29    align-self: stretch;
30  }
31}

Le bouton avec order: 999 atterrit à la fin. Sur un téléphone, il reçoit flex: 0 0 100%, car align-self: stretch seul ne l'étire, dans une rangée, que verticalement.

Récapitulatif

order ne change que l'ordre visuel et ne touche pas au DOM, tandis que align-self remplace, pour un seul élément, la valeur align-items sur l'axe secondaire. Dans la leçon suivante, tu verras ce qui se passe quand les éléments ne tiennent plus sur une seule rangée.

Dans l'éditeur ci-dessous, modifie les valeurs de order et range la dynastie des pharaons sans toucher au HTML.

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 - Order</title>
7    <link rel="stylesheet" href="style.css">
8</head>
9<body>
10    <div class="container">
11        <h1>Order - Ordre des éléments</h1>
12        <p class="subtitle">Change l'ordre d'affichage sans modifier le HTML</p>
13
14        <section class="demo-section">
15            <h2>Ordre par défaut (order: 0)</h2>
16            <div class="flex-container">
17                <div class="flex-item order-0">Élément 1</div>
18                <div class="flex-item order-0">Élément 2</div>
19                <div class="flex-item order-0">Élément 3</div>
20                <div class="flex-item order-0">Élément 4</div>
21            </div>
22            <p class="description">Éléments dans l'ordre du HTML</p>
23        </section>
24
25        <section class="demo-section">
26            <h2>Ordre modifié</h2>
27            <div class="flex-container">
28                <div class="flex-item order-4">Élément 1 (order: 4)</div>
29                <div class="flex-item order-2">Élément 2 (order: 2)</div>
30                <div class="flex-item order-1">Élément 3 (order: 1)</div>
31                <div class="flex-item order-3">Élément 4 (order: 3)</div>
32            </div>
33            <p class="description">Affichage : 3 → 2 → 4 → 1</p>
34        </section>
35
36        <section class="demo-section">
37            <h2>Order avec des valeurs négatives</h2>
38            <div class="flex-container">
39                <div class="flex-item order-0">Normal (0)</div>
40                <div class="flex-item order-minus">Premier (-1)</div>
41                <div class="flex-item order-0">Normal (0)</div>
42                <div class="flex-item order-plus">Dernier (2)</div>
43            </div>
44            <p class="description">Order peut être négatif - il apparaîtra avant les éléments avec order: 0</p>
45        </section>
46
47        <section class="demo-section practice">
48            <h2>Exercice : dynastie des pharaons</h2>
49            <p class="practice-description">Organise les pharaons par chronologie de règne</p>
50
51            <div class="timeline-container">
52                <h3>Liste chronologique des pharaons :</h3>
53                <div class="timeline">
54                    <div class="pharaoh narmer">
55                        <div class="crown">▲</div>
56                        <div class="name">Narmer</div>
57                        <div class="years">~3100 av. J.-C.</div>
58                        <div class="dynasty">Ire Dynastie</div>
59                    </div>
60
61                    <div class="pharaoh khufu">
62                        <div class="crown">▲</div>
63                        <div class="name">Khéops (Khufu)</div>
64                        <div class="years">~2580 av. J.-C.</div>
65                        <div class="dynasty">IVe Dynastie</div>
66                    </div>
67
68                    <div class="pharaoh tutankhamun">
69                        <div class="crown">▲</div>
70                        <div class="name">Toutânkhamon</div>
71                        <div class="years">~1332 av. J.-C.</div>
72                        <div class="dynasty">XVIIIe Dynastie</div>
73                    </div>
74
75                    <div class="pharaoh ramesses">
76                        <div class="crown">▲</div>
77                        <div class="name">Ramsès II</div>
78                        <div class="years">~1279 av. J.-C.</div>
79                        <div class="dynasty">XIXe Dynastie</div>
80                    </div>
81
82                    <div class="pharaoh cleopatra">
83                        <div class="crown">▲</div>
84                        <div class="name">Cléopâtre VII</div>
85                        <div class="years">~51 av. J.-C.</div>
86                        <div class="dynasty">Ptolémées</div>
87                    </div>
88                </div>
89            </div>
90
91            <div class="controls">
92                <button onclick="resetOrder()">Ordre HTML</button>
93                <button onclick="chronologicalOrder()">Chronologiquement</button>
94                <button onclick="reverseOrder()">À l'envers</button>
95                <button onclick="randomOrder()">Aléatoire</button>
96            </div>
97
98            <div class="info-box">
99                <h4>Comment fonctionne order :</h4>
100                <ul>
101                    <li>Par défaut, tous les éléments ont <code>order: 0</code></li>
102                    <li>Les éléments sont triés par ordre croissant de la valeur order</li>
103                    <li>Avec la même valeur order, l'ordre du HTML compte</li>
104                    <li>On peut utiliser des valeurs négatives</li>
105                </ul>
106            </div>
107        </section>
108    </div>
109
110    <script>
111        function resetOrder() {
112            const pharaohs = document.querySelectorAll('.pharaoh');
113            pharaohs.forEach((pharaoh, index) => {
114                pharaoh.style.order = '0';
115            });
116        }
117
118        function chronologicalOrder() {
119            document.querySelector('.narmer').style.order = '1';
120            document.querySelector('.khufu').style.order = '2';
121            document.querySelector('.tutankhamun').style.order = '3';
122            document.querySelector('.ramesses').style.order = '4';
123            document.querySelector('.cleopatra').style.order = '5';
124        }
125
126        function reverseOrder() {
127            document.querySelector('.narmer').style.order = '5';
128            document.querySelector('.khufu').style.order = '4';
129            document.querySelector('.tutankhamun').style.order = '3';
130            document.querySelector('.ramesses').style.order = '2';
131            document.querySelector('.cleopatra').style.order = '1';
132        }
133
134        function randomOrder() {
135            const pharaohs = document.querySelectorAll('.pharaoh');
136            pharaohs.forEach(pharaoh => {
137                pharaoh.style.order = Math.floor(Math.random() * 10);
138            });
139        }
140    </script>
141</body>
142</html>

Retiens : order et align-self sont les ordres spéciaux du pharaon pour certains blocs de la pyramide, des exceptions aux règles générales qui ne réorganisent jamais le catalogue, c'est-à-dire le HTML.

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. Quelle est la valeur par défaut de la propriété order pour tous les éléments flexibles ?

  2. 2. À quoi sert la propriété align-self ?

Tâches pratiques dans le jeu

  • Tri horizontal

    Ordonne la déclaration CSS qui place un élément en deuxième position :

  • Clique dans l'ordre

    Ordonne la déclaration qui centre un seul élément sur l'axe transversal :

Articles utiles