Architecture et langages Web (NFA040)

flex grow shrink basis...

Olivier Pons
(pons@cnam.fr)

2022

Lorsque qu'on applique une propriété CSS à un élément, il y a, surtout avec les flexbox beaucoup de choses qui se passent sous le capot.

Par exemple, si nous avons le code HTML suivant:

<div class="conteneurFlex">
  <div class="elementFlex">elementFlex</div>
  <div class="elementFlex">elementFlex</div>
  <div class="elementFlex">elementFlex</div>
</div>

Et que nous écrivons le CSS sur le conteneur

.conteneurFlex {   
  display: flex;
}

Toute une série de propriétés par défaut seront appliquées aux éléments .elementFlex, comme si nous avions écrit nous-mêmes le css suivant:

.elementFlex {
  flex: 0 1 auto; /* valeur par default de flex  */
}

parce que certaines propriétés ont des valeurs par défaut; ces valeur peuvent évidemment être remplacées par nos soins en écrivant du code explicite. Si nous ne savons pas que ces styles implicites sont appliqués lorsque nous écrivons notre CSS, nos résultats de mises en page peuvent devenir assez difficiles à comprendre et a gérer.

La propriété flex ci-dessus est ce que l'on appelle une propriété raccourcie.

En réalité, il s'agit de définir trois propriétés CSS distinctes en même temps.

Ce que nous avons écrit ci-dessus revient donc à écrire ceci :

.elementFlex {
  flex-grow: 0;
  flex-shrink: 1;
  flex-basis: auto;
}

Ainsi, une propriété raccourcie regroupe des propriétés CSS différentes pour faciliter l'écriture de plusieurs propriétés à la fois.

Remarque :

On à déjà manipulé des propriétés raccourcies, par exemple: border qui est un raccourci pour border-width, border-style et border-color.

ainsi

p {border:1em dashed red;}

equivaut à:

p {
    border-width:1em;
    border-style:dashed
    border-color:red;
}
<style>
p {border:1em dashed red;}
</style>

<p>exemple propriété raccourcie</p>

exemple propriété raccourcie

Quand on débute en CSS, il est souvent preferable d'utiliser les versions longues dont le nom est plus significative et donc plus facile à mémoriser. Mais, lorsqu'il s'agit de flexbox, il est plutôt recommandé d'utiliser les raccourcis car la propriété flex fait beaucoup de travail et que chacune de ses sous-propriétés interagit avec les autres.

De plus, les styles par défaut sont une bonne chose car, dans 90 % des cas, nous n'avons pas besoin de savoir ce que font ces propriétés par défaut. Par exemple, lorsque qu'on utilise les flexbox, on peut commencer par écrire quelque chose comme ceci :

.conteneurFlex {
  display: flex;
  justify-content: space-between;
}

sans se soucier des éléments .elementFlex ou des styles qui leur ont été appliqués.

Dans ce cas, nous alignons les éléments .elementFlex côte à côte, puis nous les espaçons de manière égale les uns des autres. Deux lignes de CSS suffise ici et c'est ce qu'il y a de mieux avec la flexbox et ces styles hérités , on n'a pas besoin de comprendre toute la complexité du système si on veut simplement faire la même chose dans 90 % des cas.

C'est très pratique parce que toute la 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 sont les choses intéressantes que nous pouvons faire avec elles ?

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 .elementFlex :

.elementFlex {
  flex: 0 1 auto;
}

Ces styles par défaut indiquent aux éléments .elementFlex comment s'étirer et se développer. Pour comprendre ou se rappeler se que cela fait on peut penser ces propriétés abrégées comme ceci:

.elementFlex {
    /* c'est pas du css, juste une façon de penser la règle ci-dessus  */
  flex: [flex-grow] [flex-shrink] [flex-basis];
}

ou...

.elementFlex {
        /* c'est pas du css, juste une façon de penser la règle ci-dessus  */

  flex: [max] [min] [taille idéale];
}

La première valeur est flex-grow et elle est définie à 0 car, par défaut, nous ne voulons pas que nos éléments s'étendent du tout (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 :

.conteneurFlex { 
  display: flex; 
}

.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  height:80px;
  border:solid;
}
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>grand element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
grand element
element

On a ajouté la propriété contenteditable à chaque élément .elementFlex ci-dessus pour que vous puissiez cliquer dessus et modifier les contenus et voir comment cela 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 modifions la valeur par défaut de la propriété flex-grow de 0 à 1, comme ceci :

.elementFlex {
  flex: 1 1 auto;
}

Tous les éléments se répartissent la place complète du conteneur et prendront donc une part égale de l'élément .conteneurFlex, seulement si la longueur de leur contenu est la même.


.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;

}


.elementFlex {
  background-color: green;
  padding: 10px;
  border:solid;
  height:80px;
  flex-grow:1;
}
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>grand element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
grand element
element

c'est exactement t la meme chose que d'écrire

.elementFlex {
  flex-grow: 1;
}

et en ignorant les autres valeurs parce qu'elles ont été définies par défaut de toute façon.

Cela peut être deroutant quand on commence à travailler avec des mises en page flexibles. car le flex-grow que l'on ajoute interagit (ie., son comportement depend aussi de la valeur des autres propriétés) avec des valeur par défaut que l'on n'a pas positionné. -

Maintenant, si nous voulons qu'un seul de ces éléments croisse plus que les autres, il suffit de faire ce qui suit :

.elementFlex.trois {
  flex: 5 1 auto;
}

/* ou juste */

.elementFlex.trois {
  flex-grow: 5;
}
<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  border:solid;
  height:80px;
  flex-grow:1;
}

// l'élément trois 

.elementFlex.trois {
    flex-grow:5;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>grand element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
grand element
element

dans l'exemple ci-dessus, les deux premiers éléments .elementFlex occuperont proportionnellement la même quantité d'espace, mais le troisième élément essaiera de croître jusqu'à cinq fois l'espace des autres.

C'est là que les choses se compliquent , car tout dépend du contenu des éléments .elementFlex. Même si nous définissons flex-grow:5, comme nous l'avons fait dans l'exemple ci-dessus, puis que nous ajoutons du contenu, la mise en page sera modifiée comme ci-dessous :

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  border:solid;
  height:80px;
  flex-grow:1;
}

.elementFlex.trois {
    flex-grow:5;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>un tres tres tres grand elementFlex </div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
un tres tres tres grand element
element

La deuxième colonne prend maintenant trop d'espace ! Nous reviendrons sur ce point plus tard, mais pour l'instant, il est 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.

Voyons , maintenant flex-shrink.

Rappelez-vous que c'est la deuxième valeur dans le raccourci flex :

.elementFlex {
  flex: 0 1 auto; /* flex-shrink = 1 */
}

flex-shrink indique au navigateur quelle doit être la taille minimale d'un élément; sa valeur par défaut est 1, ce qui revient à dire : "occupez toujours la même quantité d'espace". Cependant ! Si nous devions définir cette valeur à 0 comme ceci :

.elementFlex {
  flex: 0 0 auto;
}

alors on dit à cet élément de ne pas rétrécir du tout. Nous reviendrons sur cette propriété une fois que nous aurons examiné la valeur finale de la propriété raccourcie.

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 sa taille idéale.

Par défaut,on a flex-basis:auto, ce qui signifie "Utilisez ma hauteur ou ma largeur". Ainsi, lorsque nous définissons display:flexsur un conteneur .conteneurFlex

.conteneurFlex {
  display: flex;
}

//donc par default
.elementFlex {
  flex: 0 1 auto;
}

On aura, par défaut dans le navigateur :

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  height:80px;
  border:solid;
}

</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
element
element

Remarque :

Tous les éléments ont par défaut la largeur de leur contenu.
C'est parce qu'Auto veut dire 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 conteneurFlex, nous pouvons définir les éléments .elementFlex avec width : 100%, ou nous pouvons définir flex-basis:100%, ou nous pouvons définir flex-grow:1.

Chacune de ces valeurs abrégées a un impact sur les autres et c'est pourquoi il est recommandé d'utiliser lla propriété raccourcie plutôt que de définir ces valeurs indépendamment les unes des autres.

Lorsque nous écrivons quelque chose comme:

.elementFlex.trois {
  flex: 0 1 1000px;
}

Ce que nous disons au navigateur, c'est de définir la base flexible à 1000px soit "s'il te plaît, essaye d'occuper 1000px d'espace". Si ce n'est pas possible, l'élément occupera cet espace proportionnellement aux autres éléments.

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;

}


.elementFlex {
  background-color: green;
  padding: 10px;
  height:80px;
  border:solid;
}

.elementFlex.trois {
    flex:0 1 1000px;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
element
element

Remarque :

Sur les petits écrans, ce troisième élément ne fait pas 1000px !
Il s'agit en fait d'une suggestion et flex-shrink, qui demande à l'élément de se réduire à la même taille que les autres éléments, s'applique toujours

De même, l'ajout de contenu aux autres .elementFlex aura toujours un impact, comme illustré ci-dessous :

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  height:80px;
  border:solid;
}

.elementFlex.trois {
    flex:0 1 1000px;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>anticonstitutionnellement, est un mot  tres grand dans l'element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
anticonstitutionnellement, est un mot tres grand dans l'element
element

Maintenant, si nous voulions interdire à cet élément de rétrécir , nous pourrions écrire quelque chose comme ceci :

.elementFlex.trois {
  flex: 0 0 1000px;
}

Rappel :

flex-shrink est la deuxième valeur et en la mettant à 0 nous disons, "Ne rétrécis jamais". Et c'est ce qui se passe ! L'élément se détachera même du conteneurFlex parce que sa largeur ne sera jamais inférieure à 1000px :

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  height:80px;
  border:solid;
}

.elementFlex.trois {
    flex:0 0 1000px;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>grand element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
element
element

Maintenant, tout cela change si nous définissons flex-wrap dans l'élément .conteneurFlex :

.conteneurFlex {
  display: flex;
  flex-wrap: wrap;
}

.elementFlex.trois {
  flex: 0 0 1000px;
}

Nous verrons quelque chose comme ceci :

<style>
.conteneurFlex {
  background-color: orange;
  display: flex;
  padding: 10px;
  border:dotted;
  flex-wrap:wrap;
}


.elementFlex {
  background-color: green;
  padding: 10px;
  border:solid;
  height:80px;
  flex: 0 1 auto;
}

.elementFlex.trois {
    flex:1 0 1000px;
}
</style>
<div class="conteneurFlex">
  <div class="elementFlex un" contenteditable>element</div>
  <div class="elementFlex deux" contenteditable>element</div>
  <div class="elementFlex trois" contenteditable>element</div>
</div>
element
element
element

En effet, par défaut, les éléments flexibles essaieront de tenir sur une seule ligne, mais flex-wrap : wrap si ces flexibles ne peuvent pas tenir dans le même espace, ils se seront disposé sur plusieurs lignes.

Quoi qu'il en soit, il ne s'agit là que de quelques-unes des façons dont les propriétés flex interagissent et de la raison pour laquelle il est important de comprendre comment ces propriétés fonctionnent ensemble.

Chacune de ces propriétés peut affecter l'autre, et si vous ne comprenez pas le fonctionnement d'une propriété, alors vous ne comprenez pas du tout comment tout cela fonctionne.

En résumer :