Flexbox ça mange quoi en hiver ?

Bien que disponibles depuis plusieurs années, les CSS3 nous cachaient une belle surprise, quelque chose qui allait révolutionner la mise en page sur le Web.

Longtemps boudé par manque de support, le module Flexbox a finalement reçu assez d’endossements pour fonctionner à peu près partout.

N’ayez craintes, car le Saint Graal des CSS est enfin à portée de main.

Mais avant de pouvoir faire des miracles, il faut apprendre à se servir de ces nouveaux pouvoirs.

Présentation rapide du module

Historique

Comparativement à d’autres nouveautés des CSS3, le module Flexbox a vécu un très long processus de développement pour en arriver à son état actuel.

C’est en 2009 que le premier brouillon voit le jour. À ce moment là, on instancie le module avec la déclaration display : box et toutes les propriétés commencent par box-, mais la syntaxe et les concepts généraux resteront assez similaires à ceux d’aujourd’hui.

En 2011, la syntaxe change énormément. La propriété pour instancier le module devient alors display : flexbox, les autres propriétés changent leur préfixe par flex- et on a le droit à quelques étrangetés telles que des fonctions comme valeurs width: flex(1 0 100px).

C’est à la troisième refonte que la syntaxe actelle voit le jour, en 2012. Elle subit des ajustement au cours des mois et années qui suivent avec une syntaxe plus proche de celle de 2009 et abandonne les choix étranges de 2011.

En date du 1er mars 2016, le W3C détermine que le module répond aux exigences et le soumet à son processus d’approbation.

Promesses

Le module de mise en page Flexbox a été conçu pour permettre de gérer d’une manière efficace l’espacement, l’alignement, la taille et la distribution d’éléments au sein d’un conteneur, même si la taille desdits éléments est inconnue.

Voici les différentes promesses que réalise le module :

  1. Ajustements des éléments à l’espace disponible
  2. Contrôle de la direction de distribution ( → ↓ ← ↑ )
  3. Réorganisation de l’ordre des éléments
  4. Distribution sur une ligne ou plusieurs
  5. Contrôle de l’alignement des éléments

Notions de base

Conteneur flex et éléments flex

La première chose à comprendre pour démystifier Flexbox, c’est la relation entre le conteneur et ses enfants.

Dès qu’un élément reçoit la déclaration CSS display : flex ou display : inline-flex, il devient un conteneur flex. Un conteneur sert à définir le contexte d’affichage de ses éléments flex.

Tout enfant direct du conteneur flex devient automatiquement un élément flex, pas besoin d’ajouter de déclaration. D’ailleurs, utiliser la propriété display n’a aucun effet sur un élément flex (sauf display : none et flex et inline-flex).

Illustration de la relation entre le conteneur-flex et les éléments-flex

Les descendants du conteneur flex au-delà du premier niveau ne sont pas considérés comme des éléments flex, les propriétés Flexbox ne s’appliquent donc pas à eux.

Exemple : Qui est quoi ?

<div style="display:flex;">
  <span>item 1</span>
  <span>item 2</span>
  <div>
    <span>item 3</span>
    <span>item 4</span>
  </div>
</div>

Réponse :

<div style="display:flex;"> <!-- Conteneur flex -->
  <span>item 1</span> <!-- Élément flex -->
  <span>item 2</span> <!-- Élément flex -->
  <div> <!-- Élément flex -->
    <span>item 3</span>
    <span>item 4</span>
  </div>
</div>

Par contre, il est possible d’imbriquer les conteneurs flex. Donc un élément flex peut être aussi un conteneur flex :

<div style="display:flex;"> <!-- Niveau 1 -->
  <span>item 1</span> <!-- Niveau 1 -->
  <span>item 2</span> <!-- Niveau 1 -->
  <div style="display:flex;"> <!-- Niveau 1 ET 2 -->
    <span>item 3</span> <!-- Niveau 2 -->
    <span>item 4</span> <!-- Niveau 2 -->
  </div>
</div>

Les proprétés définies sur le conteneur flex servent à configurer le contexte d’affichage général des éléments flex.

Celles définies sur les éléments flex permettent de les ajuster individuellement.

L’axe principal et secondaire

Flexbox permet de contrôler la direction de la distrubution des éléments flex à l’intérieur du conteneur flex.

Pour ce faire, il y a deux concepts importants à comprendre, l’axe principal et l’axe secondaire.

Illustration des axes par défaut

Le main-axis (ou axe principal) définit le sens dans lequel les éléments flex sont distribués, avec ou sans retour à la ligne. Par défaut, le main-axis distribut les éléments de gauche à droite →, mais il peut être changé pour être de haut en bas ↓, de droite à gauche ← et de bas en haut ↑.

Illustration de l'axe principal par défaut

Le cross-axis (ou axe secondaire) définit le sens dans lequel les éléments flex sont distribués lors d’un retour à la ligne. L’axe secondaire doit forcément être dans un sens où il est perpendiculaire à l’axe principal. Par défaut, le cross-axis est défini de haut en bas ↓ et comme le main-axis, il peut être changé.

Illustration de l'axe secondaire par défaut

La ligne

Flexbox distribut les éléments flex en rangées verticales ou horizontales appélées lignes.

L’orientation des lignes est déterminée par l’axe principal et s’il y a plus d’une ligne à afficher, les lignes supplémentaires seront ajoutées dans le sens de l’axe secondaire.

Illustration de la disposition des lignes

Par défaut, Flexbox n’utilise qu’une seule ligne et y entasse tous les éléments, mais ce comportement peut être changé par une propriété du conteneur flex.

Présentation de la syntaxe actuelle

Propriétés du conteneur flex

display

La propriété display est la base du module Flexbox, c’est grâce à elle que la relation conteneur/éléments flex est établie.

display : flex | inline-flex

La valeur flex définit le conteneur flex comme un élément de type block pour l’affichage.

Comme son nom l’indique, la valeur inline-flex définit le conteneur flex comme un élément inline.

flex-direction

La propriété flex-direction permet de définir le sens de l’axe principal.

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

La valeur par défaut est row, ce qui définit une répartition des éléments flex à l’horizontale de gauche à droite →. Évidemment, row-reverse inverse la distribution, qui passe alors de droite à gauche ←.

La valeur column change l’axe principal à la verticale et établit une répartission de haut en bas ↓, alors qu’avec column-reverse elle se fait de bas en haut ↑.

Illustration des valeurs de flex-direction

flex-wrap

La propriété flex-wrap permet de configurer si les éléments flex doivent être contenus en une seule ligne ou si l’utilisation de plusieurs lignes est acceptable.

flex-wrap : nowrap | wrap | wrap-reverse

Par défaut, flex-wrap a la valeur de nowrap, ce qui force les éléments flex sur une ligne.

La valeur wrap permet, si nécessaire, que les éléments soient distribués sur plusieurs lignes sur l’axe secondaire.

Si l’axe principal est horizontal, les nouvelles lignes seront ajoutées de haut en bas ↓. S’il est vertical, elles seront ajoutées de gauche à droite →.

La valeur wrap-reverse a le même effet que wrap, sauf que la direction d’ajout des nouvelles lignes est inversée :

De bas en haut ↑ pour un axe principal horizontal et de droite à gauche ← pour un axe principal vertical.

Illustration des valeurs de flex-wrap

flex-flow

La propriété flex-flow est un raccourci qui permet de définir d’un seul coup la valeur de flex-direction et de flex-wrap.

flex-flow : "flex-direction" "flex-wrap"

justify-content

justify-content permet de controler comment les éléments flex sont disposés sur l’axe principal et comment l’espace libre est géré.

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

Les valeurs flex-start, center et flex-end regroupent respectivement les éléments flex au début, au centre ou à la fin de l’axe principal.

Avec space-between, les éléments flex sont disposés à intervalles égaux, le premier élément et le dernier élément de la ligne étant respectivement positionnés au début et à la fin de l’axe principal.

Avec space-around, l’espace libre est divisé équitablement entre chaque élément flex et disposé également autour des éléments.

Illustration des valeurs de justify-content

align-items

La propriété align-item est en quelque sorte l’équivalent de justify-content pour l’axe secondaire. Elle définit comment les éléments flex d’une ligne sont disposés sur l’axe secondaire.

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

Les valeurs flex-start, center et flex-end regroupent respectivement les éléments flex au début, au centre ou à la fin de l’axe secondaire.

Avec strech, les éléments flex sont étirés pour remplir leur ligne en hauteur ou en largeur, dépendamment du sens de l’axe secondaire.

La valeur baseline n’est pas facile à comprendre. Avec elle, les éléments sont alignés par rapport à la ligne de base de leur contenu. Mieux vaut faire des tests pour comprendre cette valeur.

Illustration des valeurs de align-items

align-content

La propriété align-content définit comment les lignes d’éléments sont disposés sur l’axe secondaire et comment l’espace libre est géré.

Cette propriété n’a aucun effet s’il n’y a qu’une seule ligne d’éléments.

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

Les valeurs flex-start, center et flex-end regroupent respectivement les lignes au début, au centre ou à la fin de l’axe secondaire.

Avec space-between, les lignes sont disposées à intervalles égaux, la première ligne et la dernière étant respectivement positionnées au début et à la fin de l’axe secondaire.

Avec space-around, l’espace libre est divisé équitablement entre chaque ligne et disposé également autour des lignes.

La dernière valeur, stretch, étire chaque ligne équitablement pour enlever l’espace restant.

Illustration des valeurs de align-content

Propriétés des éléments flex

order

Habituellement, les éléments s’affichent dans l’ordre dans lequel ils sont définis dans le DOM, mais Flexbox permet de changer ce comportement avec la propriété order.

order : 0

Par défaut, la propriété a une valeur de 0, mais n’importe quel nombre, positif ou négatif, peut être utilisé.

Les éléments flex s’affichent donc selon l’ordre établi par la valeur de la propriété order définie sur ces éléments.

Illustration de la propriété order

Note : la sélection du texte se fie sur l’ordre du DOM, ce qui cause des cas étranges avec les éléments déplacés par la propriété order.

flex-basis

La propriété flex-basis détermine la taille (hauteur ou largeur) par défaut d’un élément flex avant que l’espace restant de la ligne ne soit attribué.

La taille de l’élément fait référence à la largeur de l’élément si l’axe principal est horizontal et à la hauteur si l’axe principal est vertical.

flex-basis : 100px | 10% | 5em | 20vw | auto

Par défaut, flex-basis a une valeur de auto, ce qui implique que la dimension de l’élément est déterminée par son width ou son height.

La propriété peut prendre n’importe quelle valeur positive : pixel, em, rem, pourcentage et bien d’autres.

flex-grow

flex-grow permet de configurer la capacité des éléments flex à s’étirer au-delà de leur taille de base (déterminée par flex-basis) pour remplir l’espace inutilisé.

L’espace restant d’une ligne est divisé entre les éléments flex qui ont la propriété définie avec une valeur de 1 ou plus.

Ainsi, le nombre de parts qu’un élément prend de l’espace inutilisé correspond à la valeur flex-grow de cet élément.

Illustration de valeurs de la propriété flex-grow

flex-grow : 0

Par défaut, flex-grow a une valeur de 0, ce qui empèche l’élément flex de grandir s’il y a de l’espace disponible.

La propriété accepte comme valeur n’importe quel nombre entier égal ou supérieur à 0.

flex-shrink

À l’inverse de flex-grow, flex-shrink permet de déterminer la capacité des éléments flex a se rétrécir si leur taille de base ne leur permet pas de rentrer sur la ligne.

L’espace manquant est soustrait entre les éléments flex qui ont la propriété définie avec une valeur de 1 ou plus.

Ainsi, l’élément rétrécie à une vitesse qui correspond à la valeur flex-shrink de cet élément.

À noter qu’une valeur de 0 empêche l’élément de rétrécir, ce qui peut causer des bris de mise en page si le conteneur n’utilise qu’une seule ligne.

Illustration de valeurs de la propriété flex-shrink

flex-shrink : 1

La valeur par défaut de flex-shrink est de 1, ce qui implique que tous les éléments rapetissent au même rythme.

La propriété accepte comme valeur n’importe quel nombre entier égal ou supérieur à 0.

flex

La propriété flex est un raccourci qui permet de définir d’un seul coup la valeur de flex-grow, flex-shrink et de flex-basis.

Il est recommandé d’utiliser cette propriété plutôt que de déclarer les sous-propriétés une à une.

flex : none | "flex-grow" "flex-shrink" "flex-basis"

Par défaut, flex a une valeur de 0 1 auto, ce qui correspond aux valeurs par défaut des sous-propriétés.

Les valeurs none et auto équivalent respectivement à 0 0 auto et 1 1 auto.

La propriété peut accepter un bon nombre de valeurs et même ignorer certains paramètres, la documentation liste les différentes options disponibles.

align-self

La propriété align-self permet de modifier individuellement l’alignement par défaut qui a été déclaré par align-items.

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

Les valeurs possibles pour align-self sont les mêmes que pour la propriété align-items.

Illustration de valeurs de la propriété align-self

Cas d’utilisations

Mises en page modulaires

Réorganiser les sections d’une page Web a toujours été un défi de taille et les outils actuels sont mal adaptés pour cette tache :

Dupliquer le contenu et gérer l’affichage avec des media queries est mauvais pour le SEO. Alors que manipuler le DOM pour des opérations de cette taille est mauvais pour la performance.

Avec la propriété order, réorganiser les différents morceaux d’une interface devient d’une facilité déconcertante.

Voici un exemple très simple pour illustrer ce qu’il est possible de faire.

Grilles responsives élégantes

De la liste de produits à la galerie photo, on a tous besoin d’une bonne grille pour nos contenus. Malheureusement, les éléments inline-block et les colonnes float ne sont pas équipés pour les mises en page complexes et responsives.

Flexbox permet de concevoir facilement une grille d’éléments flexibles et s’adapte d’elle-même à l’espace disponible. Même les colonnes d’adaptent pour remplir leur ligne, sans JavaScript. La cerise sur le gâteau : le module permet un contrôle sans précédent sur chaque élément de la grille.

Modifier ou ajouter des éléments d’une navigation a toujours été une plaie : les espacements changent et plus souvent qu’autre chose, ça brise.

Si vous utilisez un CMS où la navigation est gérée de façon dynamique, vous savez que ça arrivera tôt ou tard.

En s’occupant de distribuer les éléments automatiquement, Flexbox vous évite de réajuster le tout à chaque fois qu’un changement survient ou qu’un client vous demande de faire grossir son logo. La preuve en démonstration.

Centrer des éléments

On ne compte plus le nombre de méthodes farfelues qui permettent de centrer un élément dans un conteneur, chacune avec ses conditions ou s’appliquant uniquement à certains types d’éléments.

Flexbox en ajoute une nouvelle qui marche à tout coup, même sans connaitre les dimentions de l’élément.

.conteneur{
  display: flex;
  align-items: center; /* Alignement vertical */
  justify-content: center; /* Alignement horizontal */
}

Support des navigateurs

Le support des navigateurs pour Flexbox est très bon. Actuellement tous les navigateurs modernes supportent Flexbox, même IE10 !

Le seul bémol, c’est que vous devrez prendre la peine d’utiliser les différentes syntaxes : l’actuelle, l’originale et l’intermédiaire.

La raison est simple, les navigateurs ne supportent pas tous la même version de Flexbox.

L’autre problème c’est, comme toujours, les anciennes versions d’Internet Explorer : si vous devez supporter IE9 ou plus ancien, il faut trouver des solutions alternatives.

Trucs et astuces

Autoprefixer ou mixins

La spécification du module Flexbox est passée à travers 3 versions majeures. Malheureusement pour nous, tous les navigateurs ne supportent pas la même version de la syntaxe…

C’est pourquoi des outils comme Autoprefixer ou des mixins sont des incontournables pour utiliser Flexbox.

De cette façon, vous n’avez qu’à vous soucier de la syntaxe la plus récente et l’outil s’occupera du reste.

Enfin presque, car malheureusement certains anciens navigateurs n’implémentent pas le module Flexbox de la bonne manière, ce qui cause des bugs. Heureusement ces problèmes sont répertoriés, ainsi que les solutions pour les régler.

Sélecteurs “first|last|nth-child” et propriété “order”

Les sélecteurs *-child utilisent l’ordre du DOM pour appliquer les déclarations CSS.

La propriété order change l’ordre visuel d’apparition dans le conteneur flex, mais l’ordre du DOM ne change pas.

Vous pouvez combiner les deux, mais souvenez vous que l’ordre du DOM ne change jamais.

Support des anciens navigateurs

Si vous voulez utiliser Flexbox sur des versions d’Internet Explorer inférieures à IE10, il faut être créatif.

Il n’y a pas de solution parfaite, mais pour l’instant Flexibility est probablement celle qui semble la plus prometteuse. Il s’agit un polyfill JavaScript qui permet de faire fonctionner la plupart des propriétés du module Flexbox sur IE9 et IE8. Ce polyfill est le seul qui supporte la syntaxe actuelle.

L’autre solution repose sur le principe de dégradation élégante des CSS3.

Puisque les navigateurs qui ne comprennent pas les propriétés du module Flexbox les ignoreront, il est possible de concevoir une mise en page alternative pour compenser le manque.

Ce n’est pas l’idéal, mais c’est le prix à payer pour utiliser Flexbox sur les vieux navigateurs.

En terminant

Polyvalent et pratique, le module Flexbox a le potentiel de simplifier même les mises en page les plus complexes, tout en nous évitant les solutions douteuses que nous avons apprises à accepter (bye bye clearfix).

Et bien que certains concepts de la syntaxe soient un peu dificiles à assimiler, avec de la pratique et un bon aide-mémoire, Flexbox n’aura bientôt plus de secrets pour vous.

Par contre, il ne faut pas perdre de vue que certains utilisateurs utilisent encore d’anciens navigateurs qui ne supportent pas la dernière version de Flexbox ou qui ne supportent pas le module du tout. Il devient donc impératif de penser à une solution de rechange au cas où quelque chose tourne mal, surtout quand c’est la mise en page d’un site qui est en jeu.

Amusez-vous, mais soyez responsables.