Comprendre flex-grow, flex-shrink et flex-basis
Lorsque nous appliquons une propriété CSS à un élément, il se passe beaucoup de choses en coulisses. Par exemple, disons que nous avons ce HTML :
<div class="parent">
<div class="child">Child</div>
<div class="child">Child</div>
<div class="child">Child</div>
</div>
...et nous ajoutons ce CSS :
.parent {
display: flex;
}
Techniquement, ce ne sont pas les seuls styles que nous appliquons lorsque nous écrivons la ligne de CSS ci-dessus. En fait, tout un tas de propriétés seront appliquées aux éléments .child
ici, comme si nous avions écrit ces styles nous-mêmes :
.child {
flex: 0 1 auto; /* valeurs flex par défaut */
}
Étrange ! Pourquoi ces éléments ont-ils ces styles supplémentaires qui leur sont appliqués alors que nous n'avons pas écrit ce code ? Eh bien, c'est parce que certaines propriétés ont des valeurs par défaut qui sont ensuite destinées à être remplacées par nous. Et si nous ne savons pas que ces styles sont appliqués lorsque nous écrivons le CSS, nos mises en page peuvent devenir assez déroutantes et difficiles à gérer.
La propriété flex
ci-dessus est ce que l'on appelle une propriété CSS abrégée (ou raccourcie : shorthand). En fait, ce que ça fait c'est qu'on définit trois propriétés CSS distinctes en même temps. Ce que nous avons écrit ci-dessus revient donc à écrire ceci :
.child {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
Une propriété raccourcie est donc une façon de regrouper un tas de propriétés CSS différentes pour faciliter l'écriture de plusieurs propriétés à la fois, précisément comme la propriété background
où nous pouvons écrire quelque chose comme ceci :
body {
background: url(sweettexture.jpg) top center no-repeat fixed
padding-box content-box red;
}
J'essaie d'éviter les propriétés raccourcies car elles peuvent être assez déroutantes et j'ai souvent tendance à écrire les versions longues à la main, simplement parce que mon cerveau ne parvient pas à analyser de longues lignes de valeurs de propriétés. Mais il est recommandé d'utiliser le raccourci lorsqu'il s'agit de flexbox, ce qui semble... bizarre... c'est-à-dire jusqu'à ce que vous compreniez que la propriété flex
fait beaucoup de travail et que chacune de ses sous-propriétés interagit avec les autres.
En outre, les styles par défaut sont une bonne chose car nous n'avons pas besoin de savoir ce que font ces propriétés flexbox dans 90 % des cas. Par exemple, lorsque j'utilise flexbox, j'ai tendance à écrire quelque chose comme :
.parent {
display: flex;
justify-content: space-between;
}
Je n'ai même pas besoin de me soucier des éléments enfants ou des styles qui leur ont été appliqués, et c'est super ! Dans ce cas, nous alignons les éléments enfants côte à côte, puis nous les espaçons de manière égale les uns des autres. Deux lignes de CSS nous donnent beaucoup de pouvoir ici et c'est ce qu'il y a de mieux avec flexbox et ces styles hérités — nous n'avons pas besoin de comprendre toute la complexité sous le capot si nous voulons simplement faire la même chose 90 % du temps. C'est remarquablement intelligent car toute cette complexité est cachée.
Mais qu'en est-il si nous voulons comprendre le fonctionnement réel de flexbox, y compris les propriétés flex-grow
, flex-shrink
et flex-basis
? Et quelles choses sympas pouvons-nous faire avec elles ?
Il suffit de consulter l'Almanach CSS-Tricks. Et c'est bon !
Nan, je plaisante. Commençons par un aperçu rapide et un peu simplifié, et revenons aux propriétés flex
par défaut qui sont appliquées aux éléments enfants :
.child {
flex: 0 1 auto;
}
Ces styles par défaut indiquent à cet élément enfant comment s'étirer et se développer. Mais chaque fois que je vois qu'ils sont utilisés ou remplacés, je trouve utile de penser à ces propriétés abrégées comme ceci :
/* C'est ainsi que je vois la règle ci-dessus dans ma tête */
.child {
flex: [flex-grow] [flex-shrink] [flex-basis];
}
/* ou bien comme ça... */
.child {
flex: [max] [min] [taille idéale];
}
La première valeur est flex-grow
et elle est réglée sur 0 car, par défaut, nous ne voulons pas que nos éléments s'étendent (la plupart du temps). Nous voulons plutôt que chaque élément dépende de la taille du contenu qu'il contient. Voici un exemple :
.parent {
display: flex;
}
J'ai ajouté la propriété contenteditable
à chaque élément .child
ci-dessus pour que vous puissiez cliquer dessus et saisir encore plus de contenu. Vous voyez comment ça réagit ? C'est le comportement par défaut d'un élément flexbox : flex-grow
est défini sur 0 car nous voulons que l'élément grandisse en fonction du contenu qu'il contient.
Mais ! Si nous devions changer la valeur par défaut de la propriété flex-grow de 0 à 1, comme ceci...
.child {
flex: 1 1 auto;
}
...alors, tous les éléments prendraient une part égale de l'élément .parent
, mais seulement si les longueurs de leurs contenus sont les mêmes.
C'est exactement comme si j'avais écrit :
.child {
flex-grow: 1;
}
...en laissant de côté les autres valeurs parce que celles-ci ont été définies par défaut de toute façon. Je pense que cela m'a longtemps perturbé lorsque j'ai commencé à travailler avec des mises en page flexibles. Je voyais du code qui ajoutait juste flex-grow
et je me demandais d'où venaient les autres styles.
Maintenant, si nous voulions qu'un seul de ces éléments croisse plus que les autres, il nous suffirait de faire :
.child-three {
flex: 3 1 auto;
}
/* ou bien nous pourrions simplement écrire... */
.child-three {
flex-grow: 3;
}
Ce code est-il étrange à regarder, même dix ans après l'arrivée de Flexbox dans les navigateurs ? Il l'est certainement pour moi. J'ai besoin d'une puissance cérébrale supplémentaire pour dire "Ah oui, max, min, taille idéale" lorsque je lis le raccourci, mais ça s'améliore avec le temps. Quoi qu'il en soit, dans l'exemple ci-dessus, les deux premiers éléments enfants occuperont proportionnellement la même quantité d'espace, mais le troisième élément essaiera de croître jusqu'à trois fois l'espace des autres.
C'est là que les choses deviennent étranges, car tout dépend du contenu des éléments enfants. Même si nous avons défini flex-grow
à 3
, comme nous l'avons fait dans l'exemple ci-dessus, si nous ajoutons ensuite plus de contenu, la mise en page fera quelque chose d'étrange comme ceci :
Cette deuxième colonne prend maintenant trop d'espace ! Nous y reviendrons plus tard, mais pour l'instant, il est juste important de se rappeler que le contenu d'un élément flex a un impact sur la façon dont flex-grow
, flex-shrink
et flex-basis
fonctionnent ensemble.
OK, passons maintenant à flex-shrink
. Rappelez-vous que c'est la deuxième valeur dans le raccourci :
.child {
flex: 0 1 auto; /* flex-shrink = 1 */
}
flex-shrink
indique au navigateur quelle doit être la taille minimale d'un élément. La valeur par défaut est 1, ce qui revient à dire : "Prenez la même quantité d'espace à tout moment". Cependant, si nous définissons cette valeur à 0 comme ceci :
.child {
flex: 0 0 auto;
}
...alors nous disons à cet élément de ne pas rétrécir du tout maintenant. Reste à la même taille, maudit élément ! c'est en substance ce que dit cette CSS, et c'est précisément ce qu'elle va faire. Nous reviendrons sur cette propriété dans un instant, une fois que nous aurons examiné la valeur finale de ce raccourci.
flex-basis
est la dernière valeur ajoutée par défaut dans le raccourci flex
, et c'est la façon dont nous indiquons à un élément de s'en tenir à une taille idéale. Par défaut, elle est définie sur auto
, ce qui signifie "Utilisez ma hauteur ou ma largeur". Ainsi, lorsque nous définissons un élément parent pour display: flex
...
.parent {
display: flex;
}
.child {
flex: 0 1 auto;
}
Nous aurons ceci par défaut dans le navigateur :
Vous avez remarqué que tous les éléments ont la largeur de leur contenu par défaut ? C'est parce qu'auto
dit que la taille idéale de notre élément est définie par son contenu. Pour que tous les éléments occupent tout l'espace du parent, nous pouvons régler les éléments enfants sur width : 100%
, ou nous pouvons régler flex-basis
sur 100%, ou nous pouvons régler flex-grow
sur 1.
Est-ce que ça fait sens pour vous ? C'est bizarre, hein ! En fait, oui, lorsqu'on y pense. Chacune de ces valeurs abrégées a un impact sur les autres et c'est pourquoi il est recommandé d'écrire ce raccourci en premier lieu plutôt que de définir ces valeurs indépendamment les unes des autres.
Bon, passons à autre chose. Lorsque nous écrivons quelque chose comme ceci...
.child-three {
flex: 0 1 1000px;
}
...ce que nous disons ici au navigateur, c'est de régler flex-basis
sur 1000px ou "s'il vous plaît, essayez d'occuper 1000px d'espace". Si ce n'est pas possible, l'élément occupera cet espace proportionnellement aux autres éléments.
Vous remarquerez peut-être que sur les petits écrans, ce troisième élément n'est pas réellement de 1000px ! C'est parce qu'il s'agit en fait d'une suggestion. Nous avons toujours l'option flex-shrink
appliquée, qui indique à l'élément de se réduire à la même taille que les autres éléments.
De même, l'ajout de contenu aux autres enfants aura toujours un impact ici :
Maintenant, si nous voulions empêcher cet élément de rétrécir, nous pourrions écrire quelque chose comme ceci :
.child-three {
flex: 0 0 1000px;
}
Rappelez-vous, flex-shrink
est la deuxième valeur ici et en la réglant à 0, nous disons, "Ne rétrécis jamais, grand idiot." Et ce n'est pas le cas. L'élément se détachera même de l'élément parent parce qu'il ne sera jamais plus petit que 1000px de large :
Maintenant, tout cela change si nous définissons flex-wrap
sur l'élément parent :
.parent {
display: flex;
flex-wrap: wrap;
}
.child-three {
flex: 0 0 1000px;
}
Nous verrons quelque chose comme ça :
En effet, par défaut, les éléments flexibles essaieront de tenir sur une seule ligne, mais flex-wrap : wrap
l'ignorera complètement. Maintenant, si ces éléments flex ne peuvent pas tenir dans le même espace, ils se sépareront sur une nouvelle ligne.
Quoi qu'il en soit, il ne s'agit là que de quelques-unes des façons dont les propriétés flex
s'entrechoquent et de la raison pour laquelle il est si précieux de comprendre comment ces propriétés fonctionnent sous le capot. Chacune de ces propriétés peut affecter l'autre, et si vous ne comprenez pas le fonctionnement d'une propriété, alors d'une certaine façon vous ne comprenez pas du tout comment tout cela fonctionne — ce qui m'a certainement déconcerté avant que je ne commence à creuser ce sujet !
Mais pour résumer :
👉🏿 Essayez d'utiliser le raccourci flex
👉🏿 Souvenez-vous de la taille maximale, minimale et idéale lorsque vous le faites
👉🏿 N'oubliez pas que le contenu d'un élément peut également avoir un impact sur la façon dont ces valeurs fonctionnent ensemble.