31/10/2018 10 Minutes read Tech 

Flexbox, un modèle de boîte CSS

Introduction et explications du fonctionnement du modèle de boîte CSS dit flexible : Flexbox.

Introduction

En complément des modèles de boîte classiques CSS (block et inline), il existe un modèle de boîte dit flexible : le modèle flexbox. Malgré des spécifications encore en version brouillon, au moins jusqu’au 1er septembre 2016, ce modèle est implémenté dans tous les navigateurs web et mobiles récents.

Il faut voir flexbox comme un modèle permettant d’agencer le positionnement et le dimensionnement des éléments d’un conteneur selon des règles globales au conteneur et/ou spécifiques à un élément. L’idée principale étant d’avoir des éléments flexibles au sein d’un conteneur, les éléments pouvant s’agrandir pour remplir l’espace vide ou rétrécir pour éviter une surcharge du conteneur et ce, aussi bien horizontalement que verticalement.

Peu importe les dimensions du conteneur, un élément à l’intérieur peut être défini avec une taille fixe, et côtoyer un autre élément qui, lui, sera totalement flexible et adapté au conteneur, tandis qu’un autre sera toujours collé en bas du conteneur.

Principes de flexbox

Il est possible de résumer le modèle flexbox via cette liste de principes non exhaustive :

  • un conteneur horizontal ou vertical contenant plusieurs éléments et ayant la valeur flex ou inline-flex sur sa propriété display ;
  • le conteneur peut être orienté dans les 4 directions (haut, bas, gauche, droite) ;
  • le conteneur peut disposer les éléments sur une seule ou plusieurs lignes ;
  • les éléments sont ordonnés ;
  • les éléments sont flexibles en dimensions et position à l’intérieur du conteneur, collectivement et individuellement ;
  • l’orientation verticale et horizontale des éléments dépends de l’orientation naturelle de la langue du navigateur, de la direction de l’axe principal et de la direction de l’axe secondaire.

Pour comprendre le modèle flexbox, voici la liste exhaustive des propriétés CSS et valeurs associées à appliquer sur le conteneur et ses éléments.

L’étude des propriétés se fera en suivant deux sujets principaux : le conteneur et les éléments.

Pour le conteneur, il sera question de flux de lecture puis du comportement global des éléments sur une ou plusieurs lignes.

Pour les éléments, il sera question de l’ordonnancement des éléments, puis de comportement de positionnement singulier d’un élément par rapport aux autres, surchargeant le comportement global, et enfin, du comportement de dimensionnement des éléments au sein du conteneur et par rapport aux autres.

Note : pour chaque propriété, les valeurs possibles sont séparées par le caractère | (barre verticale) et la première valeur de la liste est celle appliquée par défaut. Les valeurs entre <> (chevrons) font références aux valeurs d’une propriété et sont utilisées via un raccourci dont les différentes valeurs sont séparées par || (double barre verticale).

Le conteneur

<code>display: flex | inline-flex

Définit le comportement du conteneur. Respectivement : block ou inline.

Comportement du flux du conteneur

flex-direction : row | row-reverse | column | column-reverse

Direction du flux de lecture du conteneur.

En considérant un navigateur dont le sens de lecture est de gauche à droite (ltr), respectivement : de gauche à droite | de droite à gauche |de haut en bas | de bas en haut.

flex-wrap : nowrap | wrap | wrap-reverse

Indique si le conteneur adapte les éléments sur une seule ligne ou plusieurs si nécessaire.

Respectivement : éléments sur une seule ligne | passage à la ligne naturel | passage à la ligne inversé

flex-flow : <flex-direction> || <flex-wrap>

Notation raccourcie pour les deux propriétés précédentes.

Petites précisions sur les axes et les directions du conteneur flex

Un conteneur flex a deux axes. Un axe principal (main axe) qui indique la direction du flux et un axe secondaire (cross axe) qui lui est perpendiculaire.

Il est important de noter que l’axe principal n’est pas toujours le même en fonction de la direction. Par exemple, si la direction est row, l’axe principal est horizontal et va de gauche à droite ; mais si la direction est column-reverse, l’axe principal est vertical et va de bas en haut. Cela est important pour comprendre les différentes propriétés de disposition des éléments du conteneur.

Comportement global des éléments

justify-content : flex-start | flex-end | center | space-between | space-around

Permet d’aligner les éléments sur l’axe principal. Après le calcul de taille de chaque élément, l’espace restant est distribué dans le conteneur en fonction de cette propriété.

Respectivement :

  • flex-start : éléments concentrés au début du flux ; espace vide remplissant la fin ;
  • flex-end : éléments concentrés à la fin du flux ; espace vide remplissant le début ;
  • center : éléments concentrés au centre du flux ; espace vide distribué équitablement au début et à la fin du flux ;
  • space-between : éléments distribués dans le conteneur et séparés par l’espace vide réparti équitablement entre chaque élément ;
  • space-around : éléments distribués dans le conteneur et séparés par l’espace vide réparti équitablement autour de chaque élément ;

Attention : la différence entre space-between et space-around est mince, il s’agit simplement d’une logique de distribution et de disposition de l’espace vide.

Pour space-between, l’espace vide est placé entre deux éléments :

Pour space-around, l’espace vide est distribué autour de chaque élément :

align-items : stretch | flex-start | flex-end | center | baseline

Permet d’aligner les éléments sur l’axe secondaire.

Respectivement :

  • stretch : éléments prenant toute la place disponible sur l’axe secondaire, sous condition qu’aucune taille n’ait été donnée à l’élément ; aucun espace libre ;
  • flex-start : éléments à la taille de leur contenu et collés au début du flux secondaire ; espace libre à la fin ;
  • flex-end : éléments à la taille de leur contenu et collés à la fin du flux secondaire ; espace libre au début ;
  • center : éléments à la taille de leur contenu et au centre du flux secondaire ; espace vide distribué équitablement au début et à la fin ;
  • baseline : éléments à la taille de leur contenu et alignés sur leur baseline ; espace libre distribué autour sauf pour l’élément le plus grand qui est collé au début du flux secondaire ;

L’exemple ci-dessous montre des éléments s’adaptant à leur contenu et alignés sur leur première ligne de texte. L’élément 2 est le seul à être collé au début du flux car il est le plus grand. Les autres étant plus petits, il y a de l’espace libre autour.

Les éléments sont adaptés à leur contenu et les textes, de tailles différentes, sont alignés sur la même ligne.

Comportement global des éléments dans un conteneur multi-ligne

align-content : flex-start | flex-end | center | space-between | space-around | stretch

Permet d’indiquer le positionnement des éléments dans un conteneur multi-ligne. Le comportement est le même que pour justify-content sur l’axe secondaire.

Ci-dessous un exemple avec space-around :

Les éléments sont adaptés à leur contenu et l’espace libre est distribué autour de chacun d’entre eux.

Les éléments

Ordre des éléments

order : <nombre entier>

Initialement, les éléments sont rangés dans l’ordre d’apparition dans le markup et la valeur de la propriété est 0. Il est possible de changer cet ordre en modifiant la valeur – nombre entier positif ou négatif.

Exemple avec les éléments 1 et 2 d’une valeur à 1 et l’élément 5 d’une valeur à -1. 1 et 2 sont donc à la fin, valeur supérieur à 0 et dans l’ordre du markup : 1 est avant 2. 5 est au début avec la valeur -1.

Attention à l’ordre des éléments pour l’accessibilité et lors de la navigation au clavier, principalement dans les formulaires. Le changement d’ordre flexbox ne change pas l’ordre des éléments dans le markup et la navigation clavier continuera d’utiliser l’ordre des éléments dans le markup.

Comportement de positionnement

align-self : auto | flex-start | flex-end | center | baseline | stretch

Permet de surcharger la valeur align-items du conteneur pour un élément en particulier. Même comportement pour les valeurs.

Comportement de dimensionnement

flex-grow : 0 |

Ratio d’agrandissement d’un élément. Indique, par rapport aux autres éléments, le ratio d’espace positif qu’il pourra intégrer par rapport aux autres éléments. Par défaut, la valeur 0 indique qu’aucun espace n’est donné à l’élément.

L’espace positif correspond à l’espace vide restant dans le conteneur par rapport à la somme de la taille des éléments : l’espace disponible distribuable.

Mathématiquement, l’espace positif est divisé par la somme des valeurs flex-grow des éléments et est distribué à chaque élément en fonction de leur ratio.

flex-shrink : 1 | <nombre>

Ratio de rétrécissement d’un élément. Indique, par rapport aux autre éléments, le ratio d’espace négatif qu’il accepte de perdre par rapport à sa taille.

Par défaut, la valeur 1 indique qu’il accepte d’être rétréci jusqu’à la taille de son contenu. Ici, l’espace négatif correspond à l’espace manquant dans le conteneur par rapport à la somme des tailles des éléments : l’espace qu’il faudrait au conteneur pour que chaque taille d’élément soit résolue.

Mathématiquement, l’espace négatif est divisé par la somme des valeurs flex-shrink des éléments et il est distribué, négativement donc, à chaque élément en fonction de leur ratio.

Cette propriété n’a aucun effet si l’élément n’a pas de taille de base définie car la valeur est initialement 0 (cf. flex-basis).

flex-basis : auto | content | <'width' | ’height’>

Indique la taille initiale de l’élément, dans le sens de l’axe principal, avant la distribution d’espace libre ou manquant.

La valeur auto prend la valeur width ou height, selon la direction, définie pour l’élément. Si cette valeur est également auto, alors la valeur content est utilisée.

La valeur content adapte l’élément à son contenu.

Il est possible d’indiquer des valeurs en px, %, etc., valeurs utilisées pour les propriétés height et width d’un élément.

flex : initial | auto | none | [ <‘flex-grow'> <‘flex-shrink'> <‘flex-basis'> ]

Raccourci permettant d’utiliser les trois précédents propriétés. Il est également possible d’utiliser les mots clés suivant :

  • initial : correspondant à : 0 1 auto. L’élément ne s’agrandit pas mais peut se réduire jusqu’à la taille de son contenu avec un ratio de 1 par rapport aux autres éléments ;
  • auto : correspondant à : 1 1 auto. L’élément s’agrandit pour remplir l’espace disponible avec un ratio de 1 par rapport aux autres éléments et peut se réduire jusqu’à la taille de son contenu avec un ratio de 1 par rapport aux autres éléments ;
  • none : correspondant à : 0 0 auto. L’élément est fixe. Il ne s’agrandit pas ni ne se réduit. Cette valeur annule la flexibilité de l’élément dans un conteneur flex.

L’exemple ci-dessous montre les comportement des valeurs flex avec un conteneur flex contenant deux éléments.

Exemple 1

container {
display: flex;
}
item1 {
// flex: initial; // flex: 0 1 auto;
}
item2 {
// flex: initial; // flex: 0 1 auto;
}

Représentation d’éléments flexbox utilisant les valeurs par défaut

Les éléments n’ayant pas de taille définie sur l’axe principal, ils s’adaptent à leur contenu.

Exemple 2

container {
display: flex;
}
item1 {
flex: 1; // flex: 1 0 0
}
item2 {
flex: 2; // flex: 2 0 0
}

Représentation d’éléments flexbox avec des valeurs flex

L’élément 1 prend une division de l’espace disponible, l’élément 2 en prend 2.

Exemple 3

container {
display: flex;
}
item1 {
flex: 1 1; // flex: 1 1 0
}
item2 {
flex: 2 1; // flex: 2 1 0
}

Représentation d’éléments flexbox avec des valeurs flex

Nous obtenons le même résultat, car les éléments n’ont pas de flex-basis définie, ni de taille définie.

Exemple 4

container {
display: flex;
}
item1 {
width: 200px;
flex: 1 1; // flex: 1 1 0
}
item2 {
width: 200px;
flex: 2 1; // flex: 2 1 0
}

Représentation d’éléments flexbox avec des valeurs flex

Si l’on ajoute une taille aux éléments, cela ne change rien car flex-basis reste à 0.

Exemple 5

container {
display: flex;
}
item1 {
width: 200px;
flex: 1 1 auto; // flex: 1 1 200px
}
item2 {
width: 200px;
flex: 2 1 auto; // flex: 2 1 200px
}

Représentation d’éléments flexbox utilisant une base auto

L’élément 1 est plus grand du fait de sa taille avant redistribution d’espace (100px) et du fait que l’élément 2 reçoit moins d’espace libre car il y a 200px de moins à distribuer.

Exemple 6a

container {
display: flex;
width: 600px; // width &gt; 400px
}
item1 {
flex: 1 1 200px;
}
item2 {
flex: 2 2 200px;
}

L’élément 2 est plus grand que l’élément 1. Les éléments prennent 400px, l’espace libre est donc ajouté à la taille de base des éléments avec un ratio de 1 pour l’élément 1 et un ratio de 2 pour l’élément 2.

Exemple 6b

container {
display: flex;
width: 200px; // width &lt; 400px
}
item1 {
flex: 1 1 200px;
}
item2 {
flex: 2 2 200px;
}

L’élément 2 est plus petit que l’élément 1. Les éléments prennent 400px, l’espace manquant est donc retiré à la taille de base des éléments avec un ratio de 1 pour l’élément 1 et un ratio de 2 pour l’élément 2.

Exemple 6c

container {
display: flex;
width: 400px; // width == 400px
}
item1 {
flex: 1 1 200px;
}
item2 {
flex: 2 2 200px;
}

Les deux éléments sont de tailles égales car leurs tailles de base remplissent la totalité du conteneur.

Attention : si aucune valeur de flex-basis n’est indiquée, la valeur par défaut étant 0, la propriété flex-shrink n’aura aucun effet car il ne manquera jamais d’espace dans le conteneur.

L’exemple ci-dessus sont basés sur une valeur flex-basis indentique pour les deux éléments, mais l’on peut facilement comprendre qu’avec différentes valeurs, l’ont peut se retrouver avec un élément plus grand qu’un autre alors qu’on s’attendait à l’inverse. Il ne faut pas oublier flex-basis.

Conseils d’utilisation

Sur l’axe principal, lorsque l’attribut flex est utilisé (flex-grow au minimum à 1) sur un élément du conteneur, l’espace libre est distribué en priorité sur cet élément. Il n’y a donc plus d’espace libre à distribuer pour l’alignement sur cet axe – justify-content est donc inutile.

Il redevient utile lorsque le conteneur est en flex-wrap: wrap (ou wrap-reverse) pour aligner les élément des lignes ne contenant pas d’élément avec attribut flex-grow au minimum à 1.

Marges magiques

Sur l’axe principal, lorsqu’aucun élément n’a l’attribut flex-grow au minimum à 1, il est possible d’utiliser la valeur ‘auto’ sur les attributs margin. Cette utilisation permet de distribuer l’espace disponible entre les éléments ayant un des attributs margin à ‘auto’ (sur l’axe principal).

Sur l’axe secondaire, l’utilisation de margin: auto permet également de distribuer l’espace libre disponible sur la ligne de l’élément.

Il est ainsi facile de ‘centrer’ un élément automatiquement dans l’espace libre qui l’entoure via margin: auto.

Il est bien sur possible d’appliquer la valeur ‘auto’ uniquement à un ou plusieurs côtés de l’élément, permettant plus de précisions dans le rendu.

Conclusion

La finalité de flexbox est de rendre flexible tout ou partie d’une interface en fonction du contenu, de la taille de la fenêtre ainsi que les contraintes fonctionnelles et visuelles. Il est important de bien comprendre que tous les attributs flexbox ne sont pas tous compatibles entre eux et ne permettent pas de régler tous les problèmes d’affichages.

Il tend à devenir une des références en termes de développement web, au même titre, à plus long terme, des grid, spécification permettant la création d’interfaces sous forme de grille flexible et adaptable.

Références

Can I use Flexbox – reference

Spécifications flexbox W3C

Liste des attributs flexbox – W3C