Dans ce chapitre, on va découvrir le principe des flexbox. C'est un mode de mise en page extrêmement pratique pour aligner des éléments, les espacer, les centrer ou répartir automatiquement l'espace disponible.
On l'a déjà croisé rapidement lorsqu'on a parlé de display, mais ici on va prendre le temps de voir comment il fonctionne réellement.
Ressources
- MDN, introduction aux flexbox
- Flexbox Froggy
- Flexbox Adventure
- A Complete Guide to Flexbox sur CSS-Tricks
Le principe des flexbox
Les flexbox permettent de changer la manière dont les éléments enfants d'un conteneur sont disposés.
Au lieu d'empiler les éléments comme avec le comportement normal des blocs, on définit un axe principal et les enfants vont s'aligner le long de cet axe.
Le principe de base est toujours le même :
- on a un élément parent
- ce parent contient plusieurs enfants
- on applique
display: flexau parent
.demo {
display: flex;
}
À partir de là, les enfants se comportent différemment : au lieu de s'empiler, ils viennent se placer les uns à côté des autres.
Axe principal et axe secondaire
Quand on active un conteneur flex, il faut raisonner avec deux axes :
- l'axe principal, le long duquel les éléments vont venir se placer
- l'axe secondaire, perpendiculaire à l'axe principal il est utilisé pour gérer l'alignement.
Par défaut, l'axe principal va de gauche à droite. C'est donc le long de cet axe que les éléments vont se disposer.
La plupart des propriétés flexbox consistent ensuite à répondre à deux questions :
- comment les éléments se placent-ils sur l'axe principal ?
- comment se placent-ils sur l'axe secondaire ?
flex-direction
La propriété flex-direction permet de définir l'orientation de l'axe principal.
.demo {
display: flex;
flex-direction: row;
}
Les valeurs principales sont :
row: les éléments se placent en ligne, de gauche à droitecolumn: les éléments se placent en colonne, de haut en basrow-reverse: les éléments se placent de droite à gauchecolumn-reverse: les éléments se placent de bas en haut
Ce point est fondamental, car toutes les autres propriétés dépendent de cet axe.
justify-content
justify-content permet de positionner les éléments le long de l'axe principal.
Par défaut, les éléments sont placés au début de l'axe.
.demo {
display: flex;
justify-content: center;
}
Les valeurs les plus utiles sont :
flex-start: au début de l'axeflex-end: à la fin de l'axecenter: au centrespace-between: espace réparti entre les élémentsspace-around: espace autour des élémentsspace-evenly: espace uniforme partout
⚠️ Il faut bien retenir que justify-content suit toujours l'axe principal. Si flex-direction passe en column, justify-content agit alors verticalement.
align-items
align-items permet de positionner les éléments sur l'axe secondaire (l'axe perpendiculaire).
.demo {
display: flex;
align-items: center;
}
Les valeurs principales sont :
flex-startflex-endcenterbaselinestretch
align-items: flex-start;
align-items: flex-end;
align-items: center;
align-items: baseline;
align-items: stretch;
Le cas de baseline
baseline aligne les éléments selon la ligne de base du texte. C'est surtout utile lorsque les éléments n'ont pas tous la même taille de police.
Le cas de stretch
stretch est la valeur par défaut. Elle fait en sorte que les enfants s'étirent pour occuper tout l'espace disponible sur l'axe secondaire. Cela ne fonctionne que si les enfants n'ont pas déjà une taille fixée sur cet axe.
Le retour à la ligne avec flex-wrap
Par défaut, un conteneur flex essaie de garder tous ses enfants sur une seule ligne.
.demo {
display: flex;
flex-wrap: nowrap;
}
La valeur par défaut est nowrap, ce qui signifie qu'en cas de manque de place, les éléments vont se rétrécir. Si on veut autoriser le retour à la ligne :
.demo {
display: flex;
flex-wrap: wrap;
}
Les valeurs possibles sont :
nowrapwrapwrap-reverse
flex-wrap: nowrap;
flex-wrap: wrap;
flex-wrap: wrap-reverse;
wrap-reverse inverse simplement l'ordre visuel des lignes.
align-content
Quand flex-wrap crée plusieurs lignes, on peut contrôler la manière dont les lignes elles-mêmes se répartissent avec align-content.
.demo {
display: flex;
flex-wrap: wrap;
align-content: center;
}
Les valeurs sont très proches de celles de justify-content :
flex-startflex-endcenterspace-betweenspace-aroundspace-evenly
Attention à ne pas confondre :
align-itemsaligne les éléments dans une lignealign-contentaligne les lignes entre elles
Et comme toujours, l'effet dépend de l'orientation de l'axe.
gap
Pour créer de l'espace entre les éléments, on peut utiliser gap.
.demo {
display: flex;
gap: 20px;
}
Si on veut distinguer l'espace entre les lignes et celui entre les colonnes :
row-gap: 10px;
column-gap: 20px;
Et la forme raccourcie :
gap: 10px 20px;
Ici :
- la première valeur correspond au
row-gap - la seconde au
column-gap
gap est souvent plus propre que de bricoler avec des marges sur les enfants.
Les raccourcis du conteneur
Comme souvent en CSS, il existe des propriétés raccourcies.
Par exemple :
flex-flow: row wrap;
Cette propriété combine :
flex-directionflex-wrap
Les propriétés appliquées aux enfants
Jusqu'ici, on a vu les propriétés du conteneur. Mais les enfants flex peuvent eux aussi avoir des réglages spécifiques.
align-self
align-self permet à un enfant de se positionner différemment des autres sur l'axe secondaire.
.item:nth-child(2) {
align-self: flex-end;
}
Ici, seul le deuxième élément se place à la fin de l'axe secondaire.
Les valeurs sont les mêmes que pour align-items.
C'est pratique lorsqu'on veut casser ponctuellement l'alignement défini sur le parent.
flex-grow
flex-grow permet à un enfant de grandir pour occuper l'espace libre.
.item {
flex-grow: 1;
}
Le navigateur calcule l'espace restant dans le conteneur, puis le distribue entre les enfants qui ont une valeur de flex-grow supérieure à 0.
Par défaut :
flex-grow: 0;
Si un seul élément a flex-grow: 1, il récupère tout l'espace restant.
Si plusieurs éléments ont flex-grow, l'espace est réparti selon leurs proportions :
.item1 {
flex-grow: 1;
}
.item2 {
flex-grow: 2;
}
Ici, le second élément recevra deux fois plus d'espace supplémentaire que le premier.
flex-shrink
flex-shrink fait l'inverse : il permet à un enfant de rétrécir si l'espace manque.
.item {
flex-shrink: 1;
}
Par défaut, les éléments flex ont justement cette capacité de rétrécir pour tenir sur une ligne.
Si on ne veut pas qu'un élément rétrécisse :
.item {
flex-shrink: 0;
}
Dans ce cas, ce sont les autres éléments qui devront encaisser la réduction.
Comme pour flex-grow, on peut jouer avec des ratios.
flex-basis
flex-basis permet de définir la taille de base d'un élément avant que l'espace libre ou manquant soit distribué.
.item {
flex-basis: 100px;
}
On peut le voir comme une largeur de référence pour le calcul flex.
Dans beaucoup de cas, la largeur ou la hauteur de l'élément suffit déjà. Mais flex-basis devient utile quand on veut dissocier la taille de base du comportement final.
La propriété raccourcie flex
Les propriétés flex-grow, flex-shrink et flex-basis peuvent être regroupées :
flex: 1;
flex: 1 1 auto;
flex: 1 0 200px;
La lecture est la suivante :
- première valeur :
flex-grow - deuxième valeur :
flex-shrink - troisième valeur :
flex-basis
Cette forme raccourcie est très fréquente en pratique.
order
La propriété order permet de changer l'ordre visuel des éléments.
.item1 {
order: 2;
}
.item2 {
order: 1;
}
.item3 {
order: 3;
}
Les éléments seront affichés selon la valeur numérique la plus petite vers la plus grande.
Par défaut :
order: 0;
On peut aussi utiliser des valeurs négatives pour faire remonter un élément avant les autres.
Point de vigilance sur order
order change seulement l'ordre visuel. L'ordre HTML, lui, ne change pas. Cela peut provoquer des comportements surprenants lors :
- de la sélection de texte
- de la navigation au clavier
- de certaines interactions d'accessibilité
Il faudra donc être vigilant lors de l'utilisation de cette propriétée.
inline-flex
Comme pour block et inline, il existe une variante :
display: inline-flex;
Dans ce cas, le conteneur garde la logique flex, mais il se comporte lui-même comme un élément inline.
Cela signifie notamment qu'il prend par défaut la largeur de son contenu, au lieu d'occuper toute la largeur disponible.
Ce n'est pas le cas le plus fréquent, mais c'est parfois utile pour certains composants.
Exemple concret : un menu de navigation
Un bon cas d'usage des flexbox, c'est un menu.
Supposons une navigation qui contient plusieurs liens. Si on laisse le comportement normal des éléments inline, l'espacement dépend souvent des espaces présents dans le HTML, ce qui n'est pas idéal.
Avec flexbox, on peut reprendre la main sur l'alignement.
nav {
display: flex;
justify-content: space-evenly;
}
Cela permet de répartir les liens de manière uniforme.
Une autre approche consiste à faire grandir chaque lien :
nav {
display: flex;
}
nav a {
flex-grow: 1;
text-align: center;
padding: 10px;
}
Dans ce cas, chaque lien prend la même place disponible, ce qui facilite aussi la création d'un effet de survol sur toute la largeur de la zone.
Par exemple :
nav a:hover {
background: rgba(255, 255, 255, 0.2);
}
Cette approche donne souvent un résultat plus propre qu'un simple alignement d'éléments inline.
Ce qu'il faut retenir
Les flexbox servent à organiser les enfants d'un conteneur le long d'un axe principal.
Les propriétés du parent permettent notamment de :
- choisir la direction avec
flex-direction - distribuer les éléments avec
justify-content - les aligner sur l'axe secondaire avec
align-items - autoriser le retour à la ligne avec
flex-wrap - espacer les éléments avec
gap
Les propriétés des enfants permettent de :
- modifier ponctuellement l'alignement avec
align-self - faire grandir un élément avec
flex-grow - le faire rétrécir avec
flex-shrink - définir une base de calcul avec
flex-basis - changer son ordre visuel avec
order
Au début, ces propriétés peuvent sembler un peu abstraites et on aura tendance à les mélanger assez souvent. Mais avec la pratique vous apprendrez les cas d'usages et vous verrez le rôle de chacune de ces propriétés, ce qui aidera grandement à les mémoriser.