Vous connaissez certainement le modèle de boîte classique en CSS et ses dispositions de type “block” ou “inline”, sachez que Flexbox CSS3 a été conçu pour étendre ce périmètre en introduisant un nouveau modèle de boîte distinct, que l’on appellera “le Modèle de boîte flexible”.
En février 2016 est sorti mon livre entièrement dédié à Flexbox. Il se nomme "CSS3 Flexbox : plongez dans les CSS modernes" et je vous recommande bien évidemment sa lecture afin de comprendre tous les rouages de ce positionnement révolutionnaire, et d'en maîtriser tous les aspects.
Au sein de ce schéma, on ne raisonne plus en “block” ou “inline”, ni même en float
ou autres types de boîtes “classiques” CSS, mais en “Modèle de boîte flexible”, dont les quatre possibilités principales sont :
- Distribution des éléments horizontale ou verticale, avec passage à la ligne autorisé ou non,
- Alignements et centrages horizontaux et verticaux, justifiés, répartis,
- Réorganisation des éléments indépendamment de l’ordre du flux (DOM),
- Gestion des espaces disponibles (fluidité).
Note : ce tutoriel a été initialement rédigé en octobre 2010. Il a subi une refonte intégrale en décembre 2014 pour se mettre à jour.
En action !
Flexbox (le modèle de boîte flexible) se fonde schématiquement sur une architecture de ce type :
- Un "flex-container" permettant de créer un contexte général d’affichage,
- Un ou plusieurs "flex-item" qui ne sont rien d’autre que les enfants directs du conteneur, quels qu’ils soient.
Le "flex-container", qui définit le contexte global de modèle de boîte flexible, est tout simplement n’importe quel élément HTML doté de la déclaration display: flex;
ou display: inline-flex;
.
Ses enfants deviennent alors automatiquement (inutile de leur déclarer quoi que ce soit) des éléments de type "flex-item" :
.container {
display: flex;
}
Un élément "flex-item" n’est plus considéré comme un “bloc” ou un “inline” classique (d’ailleurs les valeurs de display
autre que none
, et même certaines propriétés telles que float
n’ont plus d’effet sur lui).
Compatibilité
N’ayons pas peur des mots : le module Flexbox est plutôt très bien reconnu par les navigateurs, même certains glorieux anciens et même sur les mobiles en général, comme en témoigne l’excellente ressource CaniUse.com.
Le seul retardataire est Internet Explorer qui ne supporte pas cette spécification pour ses anciennes versions (inférieures à IE10). Cela est éventuellement bloquant pour certains projets destinés à des ordinateurs de bureau.
Tableau des compatibilités
Standardisation
L’état de l’art de la standardisation de “Flexible Box Layout Module” est pour le moins pittoresque tant il a connu de rebondissements.
Pour résumer, après trois refontes complètes depuis sa création en 2009, Flexbox était quasiment finalisé en 2012 (la spécification était au stade de “Candidate Recommandation”), puis, en septembre 2014 a été rétrogradé au stade de “Last Call Working Draft” (brouillon en dernier appel).
Pourquoi ce retour en arrière ?
Parce que les éditeurs de la spécification semblent vraiment souhaiter que ce module “ait de la gueule”, qu’il devienne une réelle solution à l’ensemble des contraintes actuelles de mise en forme CSS. Contraintes qui datent parfois de plus de 15 ans, comme le centrage vertical par exemple.
Est-ce grave ou bloquant ? Certainement pas, à condition de prendre quelques précautions sous la forme d’un outil génial qu’est Autoprefixer.
Distribution et axe principal
La distribution, c’est à dire le sens d’affichage horizontal ou vertical des éléments "flex-items" est définie par la propriété flex-direction
dont les valeurs peuvent être :
-
row
(distribution horizontale, valeur par défaut) -
row-reverse
(distribution horizontale inversée) -
column
(distribution verticale) -
column-reverse
(distribution verticale inversée)
Cette propriété s’applique au "flex-container" et détermine l’axe principal du modèle de boîte flexible.
.container {
display: flex;
flex-direction: column;
}
Démonstration flex-direction: column
La propriété flex-wrap
définit si le contenu sera distribué sur une seule ligne (ou colonne selon l’axe principal) ou sur plusieurs lignes. En clair, si les "flex-items" ont le droit de passer à la ligne ou non.
Les valeurs de flex-wrap
sont :
-
nowrap
(les éléments ne passent pas à la ligne, valeur par défaut) -
wrap
(les éléments passent à la ligne dans le sens de lecture) -
wrap-reverse
(les éléments passent à la ligne dans le sens inverse)
.container {
display: flex;
flex-wrap: wrap-reverse;
}
Démonstration flex-wrap: wrap-reverse
À noter qu’il existe une propriété raccourcie flex-flow
qui regroupe flex-direction
et flex-wrap
.
/* affichage en ligne et passage à la ligne autorisé */
.container {
flex-flow: row wrap;
}
Alignements
Flexbox propose de gérer très finement les alignements et centrages, en différenciant les deux axes d’affichage de cette manière :
-L’alignement dans l’axe principal est traité via la propriété justify-content
- L’alignement dans l’axe secondaire est géré avec align-items
Ces deux propriétés s’appliquent au "flex-container".
Axe principal : justify-content
Les alignements dans l’axe de lecture principal sont définis à l’aide de la propriété justify-content
, dont les valeurs possibles sont :
-
flex-start
(éléments positionnés au début du sens de lecture, valeur par défaut) -
flex-end
(éléments positionnés à la fin) -
center
(position centrale) -
space-between
(répartition “justifiée”) -
space-around
(variante de répartition “justifiée”)
/* éléments positionnés en bas du conteneur */
.container {
flex-direction: column;
justify-content: flex-end;
}
Axe secondaire: align-items
Dans l’axe secondaire, les alignements sont régis via la propriété align-items
, dont les valeurs sont :
-
flex-start
(au début) -
flex-end
(à la fin) -
center
(au centre) -
baseline
(généralement identique àflex-start
) -
stretch
(étirés dans l’espace disponible, valeur par défaut)
/* éléments étirés (valeur par défaut) */
.container {
flex-direction: column;
align-items: stretch;
}
Traiter les cas particuliers : align-self
La propriété align-self
, permet de distinguer l’alignement d’un "flex-item" de ses frères. Les valeurs de cette propriété sont identiques à celles de align-items
.
/* seul le paragraphe sera à droite */
.container {
align-items: stretch;
}
p {
align-self: flex-end;
}
Propriété margin
La propriété margin
lorsqu’elle est affectée à un "flex-item" ouvre de nouvelles perspectives, notamment dans l’axe vertical puisque Flexbox n’est plus lié à un sens de lecture en particulier.
En clair, il devient possible de positionner un élément en bas de son conteneur à l’aide d’un margin-top: auto
, ou mieux : centrer à la fois horizontalement et verticalement via un simple margin: auto
.
/* paragraphe centré horizontalement et verticalement */
.container {
display: flex;
}
.container > p {
margin: auto;
}
Ordonnancement
L’une des fonctionnalités les plus avant-gardistes du modèle d’affichage Flexbox est de pouvoir réordonner à sa guise chacun des éléments indépendamment grâce à la propriété order
.
Les valeurs de order
agissent telles des pondérations : les éléments dont la valeur est la plus forte se trouveront en bas de la pile.
La propriété order
s’applique aux "flex-items" et sa valeur initiale est 0
.
/* le premier de la liste s'affichera en bas de pile */
li:first-of-type {
order: 1;
}
Flexibilité
Cela ne devrait étonner personne, la notion de flexibilité constitue le fondement du module de positionnement Flexbox, et c’est là qu’intervient l’indispensable propriété flex
.
La propriété flex
est un raccourci de trois propriétés, flex-grow
, flex-shrink
et flex-basis
, qui s’appliquent aux "flex-items" et dont les fonctionnalités sont:
-
flex-grow
: capacité pour un élément à s’étirer dans l’espace restant, -
flex-shrink
: capacité pour un élément à se contracter si nécessaire, -
flex-basis
: taille initiale de l’élément avant que l’espace restant ne soit distribué.
Par défaut, les valeurs de ces propriétés sont : flex-grow: 0
, flex-shrink: 1
et flex-basis: auto
.
En clair, les flex-items
n’occupent initialement que la taille minimale de leur contenu.
Pour rendre un élément flexible, il suffit de lui attribuer une valeur de flex-grow
(ou flex
en raccourci) supérieure à zéro.
Cet élément occupera alors l’espace restant au sein de son conteneur :
/* .salade occupera l'espace restant */
.salade {
flex: 1;
}
Plusieurs éléments peuvent être rendus flexibles et se répartir l’espace restant. L’espace disponible est alors tout simplement distribué entre les éléments flexibles.
Bonus : BFC
En guise de bonus, sachez que le modèle de boîte flexible dispose également de sérieux atouts lorsqu’il s’agit de dompter ces fichus flottants qui débordent tout le temps.
Les éléments "flex-container" et "flex-item" construisent un Block Formatting Context (BFC), ou plus exactement un Flex Formatting Context dont les avantages sont similaires et décrits dans cet article. :
- un flottant ne déborde pas d’un "flex-container" ni d'un "flex-item",
- un "flex-container" ou un "flex-item" ne s’écoule pas autour d’un flottant (ils demeurent à côté),
- il n’y a pas de fusion de marges.
Conclusion
Flexbox est une spécification vaste et complexe, nous n’en n’avons démontré que les parties les plus utiles au quotidien mais d’autres recoins restent à explorer et seront dévoilés au fur et à mesure de leur support avec les navigateurs.
Quoi qu’il en soit, le positionnement Flexible Layout regroupe de nombreuses bonnes pratiques et attentes des webdesigners et intégrateurs depuis de longues années.
Dès aujourd’hui (ou dans un avenir proche selon votre cible), il constitue sans aucun doute la méthode de positionnement la plus pratique et polyvalente qui n’ait jamais existé en CSS.
Ressources
Voici quelques ressources externes pour en savoir plus sur ce positionnement très polyvalent :
Articles et tutoriels connexes
- W3C : Spécification Flexbox Module
- Jack in the flexbox : une galerie de démonstrations dédiée à Flexbox
- Solved by Flexbox : des problèmes CSS classiques réglés grâce à Flexbox
- Flexyboxes : un bac à sable pour tester Flexbox
- Flexbox Adventures : un article anglais très détaillé sur les subtilités de Flexbox
- Flexbugs : les bugs connus de flexbox et comment les contourner
Commentaires
Ça peut être intéressant pour des adaptations sur mobile via les media queries, comme pour cette liste :
http://codepen.io/simurai/pen/dvklJ
Ok, avec un outil comme LESS est il possible de paramétrer l'ensemble des règles intégrant tout les préfixe navigateur?
Je pense que oui, mais cela nous permet d’être rétrocompatible jusqu’où pour les principaux navigateur?
Est est ce que KNACSS intègre ces réglages (pré paramétrage des préfixes Flexbox)?
Merci
@jutoto : "Est est ce que KNACSS intègre ces réglages (pré paramétrage des préfixes Flexbox)?" --> Oui :)
@Raphael & @jutoto : Pour avoir pas mal expérimenté Flexbox, il faut rester prudent sur l'intégration des différentes syntaxes via un préprocesseur (LESS) : certaines propriétés, valeurs, sont parfois très différentes (en particulier avec les quelques IE qui acceptent Flexbox...), et ne permettent ainsi pas toujours la factorisation. Néanmoins, l'essentiel des propriétés du module Flexbox se factorisent assez bien :)
Au passage, j'en profite pour rappeler qu'un bug a été signalé récemment, avec les dernières mises à jour de Firefox : https://bugzilla.mozilla.org/show_bug.cgi?id=1043520. La solution serait alors un *{min-height:0;min-width:0;}, que j'ai pu testé avec soulagement...
En bref, à mon sens, Flexbox est un outil puissant, mais il faut rester prudent. Baser un layout sur Flexbox peut être dangereux, tant les rendus des navigateurs, et le support, peuvent être changeants.
Merci pour l'update de l'article. Je viens de passer plusieurs heures à expérimenter Flexbox, et j'ai l'impression d'être loin d'en avoir fait le tour.
Un point déjà qui m'échappe : en pratique, quelle différence entre flex-basis et width ? Dans mes différents essais, j'ai beau échanger ces 2 propriétés, j'obtiens toujours le même résultat.
Si quelqu'un pouvait me donner un cas où une valeur de width ne donnerait pas le même résultat que la même valeur avec flex-basis, ça m'aiderait certainement mieux à comprendre l'intérêt réel de cette nouvelle propriété et ce qu'elle a de spécifique.
Oh mais un grand OUI !
Merci Raphael pour le petit Jack.
Media queries au placard :)
@soykje : "Baser un layout sur Flexbox peut être dangereux, tant les rendus des navigateurs, et le support, peuvent être changeants."
> À vrai dire ce n'est pas vraiment le boulot de Flexbox de créer des gabarits. Cette tâche est prévue pour un autre module CSS3 : "Grid Layout Module"... dont le support est malheureusement trop faible aujourd'hui.
@sacripant : de souvenir, sur un flex-item un flex-basis explicite prend toujours le pas sur la propriété width (mais demeure compatible avec min et max-width).
Merci beaucoup pour ce tutoriel. Je pense qu'il va m'être très utile car j'essaye de rattraper mon retard sur le responsive web design.
Très instructif. Je me demandais du coup s'il existait un moyen quelconque, lorsqu'on a un conteneur avec un display:flex; et un flex-flow:row wrap;, et à l'intérieur une liste d'un nombre indéterminé d’éléments, ayant tous la même taille, répartis sur plusieurs lignes, et occupant toute la largeur du conteneur (ayant donc un flex:1; si j'ai bien compris), de faire en sorte que les éléments de la dernière ligne aient la même largeur que les éléments des lignes du dessus au lieu de s'agrandir et d'occuper toute la largeur de cette dernière ligne?
J'ai fait un exemple en javascript pour aider à comprendre au cas où ça ne serait pas assez clair : http://jsfiddle.net/b92v5x1v/ (on peut faire ... la largeur de la fenêtre pour éventuellement avoir une meilleur idée de comment ça doit réagir). L'effet à obtenir me semble bien utile.
@parsimonhi : je remets le lien qui a mal été interprété semble-t-il http://jsfiddle.net/b92v5x1v/
@parsimonhi : non, malheureusement je ne crois pas. Mais j'aime bien ta bidouille JS ! ;)
Raphael
J'ai essayé le margin: auto et rien ne se passe
Merci de m'aider,j'ai du manquer quelque chose
Cordialement
Merci pour cet article fort instructif.
Pour ceux que ca intéresserait, voici un pense-bête sympa sur Flexbox: http://jonibologna.com/flexbox-cheatsheet/
@jpdollo : La page de démo fonctionne chez toi ? Tu testes sur quel navigateur ? Tu as bien pensé aux préfixes, comme indiqué ?
@Raphael : Magnifique découverte concernant moi qui n’arrêtais pas de me poser des questions sur les nouveaux designs avec une multitude de boites je vais m'y mettre. Merci
Bonjour,
j'ai bien suivi l'article mais j'ai une question la propriété flex s'applique sur le flex-container ou sur flex-item?
@Raphael : Merci pour ce super tutoriel. Néanmoins, il me semble qu'il y a une petite incohérence concernant l'utilisation de la propriété "flex" :
La propriété flex est un raccourci de trois propriétés, flex-grow, flex-shrink et flex-basis, qui s’appliquent au flex-container.
Cependant, tu utilises ces propriétés sur des "flex-items" juste après... une explication ?
Excellent tutoriel !!! Cependant, comme l'a souligné Oliboy50, une petite erreur s'est glissée sur l'utilisation de la propriété "flex". En fait "flex" s'applique à un "flex-item" au lieu du "flex-container".
@Oliboy50 : Raphael a corrigé cette erreur que je lui ai signalée : la propriété flex s'applique aux flex-items et non pas au flex-container ;)
Merci pour cet excellent tutoriel !
Sinon sur la partie "Propriété margin", la propriété que l'on doit définir est margin-bottom :
"...., il devient possible de positionner un élément en bas de son conteneur à l’aide d’un [margin-top: auto]".
Bonjour,
Le "Gabarit flexible" semble ne pas fonctionner correctement sur ie11 et ie 10.
La solution pour fixer le problème ajouter height :100vh à body
Bonne journée
Subtilité à préciser peut-être :
flex: 1;
équivaut en réalité à
flex-grow: 1; flex-shrink: 1, flex-basis: 0;
même si la valeur par défaut de flex-basis est en elle-même auto.
Et par ailleurs, il y a ces trois valeurs prédéfinies :
none => 0 0 auto.
auto => 1 1 auto.
initial => 0 1 auto.
Salut à tous,
mes tests de compatibilité de flexbox montrent qu'avant la 4.4.4 sur Android, l'affichage plante lamentablement.
Testant sur émulateur Android seulement (www.genymotion.com), j'arrive même à faire planter le navigateur natif quand Android est en 4.3.x ou antérieur.
Quelqu'un peut-il confirmer mon analyse ?
Merci pour cette article!
Excellente synthèse merci.