CSS : mise en page avec l'outil flexbox

Le positionnement des boites a toujours été en CSS le point le plus délicat.
Les développeurs web ont longtemps utilisé les tableaux HTML pour positionner textes et images.
Puis le CSS a proposé différentes techniques de positionnement : fixe, absolu, relatif

Mais beaucoup de développeurs WEB utilisaient la propriété float pour positionner des éléments block alors que c'est un mode de positionnement très limité et qui était initialement prévu pour disposer un élément inline (une image par exemple) dans un élément "block" (un DIV par exemple).
Nous avons vu aussi qu'en transformant des boites en éléments "inline-block" on pouvait aussi réaliser une mise en page correcte.

Excellent nouvelle : CSS3 introduit l'outil flexbox (boites flexibles) qui vise à simplifier la mise en la page.

Ce qui est remarquable c'est que tous les navigateurs récents (même Edge de MS) interprètent correctement les propriétés relatives aux boites flexibles sans même avoir besoin de préfixer celles-ci.

Distribution des boites selon un axe

Premier exemple : distribution selon un axe horizontal

Le code HTML

<body> <h2>Trois boites flexibles disposées horizontalement</h2> <div id ="principale"> <div id="boite1"> <p>Post hanc adclinis Libano monti Phoenice, regio plena gratiarum et venustatis, urbibus decorata magnis et pulchris; in quibus amoenitate celebritateque nominum Tyros excellit, Sidon et Berytus isdemque pares Emissa et Damascus saeculis condita priscis. </div> <div id="boite2"> <p>Et quoniam mirari posse quosdam peregrinos existimo haec lecturos forsitan, si contigerit, quamobrem cum oratio ad ea monstranda deflexerit quae Romae gererentur, nihil praeter seditiones narratur et tabernas et vilitates harum similis alias, summatim causas perstringam nusquam a veritate sponte propria digressurus. Hoc inmaturo interitu ipse quoque sui pertaesus excessit e vita aetatis nono anno atque vicensimo cum quadriennio imperasset. natus apud Tuscos in Massa Veternensi, patre Constantio Constantini fratre imperatoris, matreque Galla sorore Rufini et Cerealis, quos trabeae consulares nobilitarunt et praefecturae. </div> <div id="boite3"> <p>Nihil morati post haec militares avidi saepe turbarum adorti sunt Montium primum, qui divertebat in proximo, levi corpore senem atque morbosum, et hirsutis resticulis cruribus eius innexis divaricaturn sine spiramento ullo ad usque praetorium traxere praefecti. </div> </div> </body>

Attention notez que le texte de la deuxième boite est beaucoup plus long que celui dans les deux autres blocs.

Le code CSS

#principale { display : flex; flex-direction : row; border:1px solid red;} div#boite1 {background : lime ; } div#boite2 {background : pink ; } div#boite3 {background : coral ; } p{margin : 10px ; font-size : 14pt; }

La grande nouveauté est la première règle de style : #principale { display : flex; flex-direction : row;}.
Ce qui veut dire que l'élément identifié principale est le conteneur de boites flexibles (display : flex) et que ces dernières seront disposées selon un axe horizontal (flex-direction : row).

Pour aucune des trois boites flexibles je n'ai précisé de hauteur et de largeur ... C'est CSS qui gère ! Observez le rendu !

Les 3 blocs ont la même hauteur ; la largeur totale est celle du conteneur ; la largeur de chaque boite est fonction de son contenu ; les blocs sont collés.

Exemple 2 : distribution selon un axe vertical

Le code de la page

Le code HTML est strictement le même que celui de l'exemple précédent.

Dans la feuille de style la première règle change !

#principale { display : flex; flex-direction : column;border:1px solid red;}

Seule différence avec l'exemple précédent : flex-direction:column.
Ce qui signifie que les blocs flexibles ne sont pas côte à côte mais les uns en dessous des autres. Observez le rendu !

Les trois blocs ont la même largeur (celle du conteneur); la hauteur de chaque boite est ajustée automatiquement à son contenu ; les blocs sont toujours collés.

Les trois boites ont la même largeur

Nous souhaitons que les trois boites enfants aient toutes la même largeur : 30% de celle du conteneur.

Première solution

Le code HTML est inchangé !

La feuille de style interne :

#principale {display : flex; flex-direction : row; border:1px solid red;} div#boite1 {background : lime ; } div#boite2 {background : pink ; } div#boite3 {background : coral ; } #boite1, #boite2, #boite3 {width : 30%;} p{margin : 10px ; font-size : 14pt; }

Par rapport à l'exemple 1 il y a un nouvelle règle de style supplémentaire : celle qui fixe la largeur à 30% de chaque boite enfant. Observez le rendu !

C'est pas très joli car les boites sont calées à gauche ; une répartition équilibrée des blocs serait préférable.

Bonne solution

Il suffit de modifier la première règle de style :

#principale {...;justify-content : space-between; ...}

Rajout d'une propriété : justify-content : space-between Observez le rendu !

Les trois blocs sont alors répartis sur toute l'étendue de l'axe principal (marges entre les blocs mais pas aux extrémités).
C'est CSS qui gère la taille des marges !
J'aurais l'occasion de revenir sur la propriété justify-content un peu plus loin dans ce chapitre.

Exemple 3 : effets graphiques

La propriété flex-direction peut prendre deux autres valeurs : row-reverse et column-reverse (c'est à dire dans l'ordre inverse que celui indiqué par le code HTML).

Dans l'exemple ci-dessous dès que vous cliquez dans le conteneur l'ordre des boites est inversé par rapport à la situation initiale et les marges aux extrémités disparaissent.

Le code CSS :

	#principale { display : flex;  flex-direction : row; justify-content : space-around;}
	#principale:active {flex-direction : row-reverse; justify-content : space-between;}
	...
	#boite1, #boite2, #boite3 {width : 30%;} 

Remarquez que j'ai utilisé la propriété justify-content avec une autre valeur : space-around (marges entre blocs mais aussi aux extrémités).
Observez le rendu !

Dès que vous cliquez dans le conteneur l'ordre des boites est inversé par rapport à la situation initiale et les marges aux extrémités disparaissent.

Disposition selon deux axes

Le code HTML de la page

<body> <section> <article> <p>Post hanc ... </article> <article> <p>Et quoniam ... </article> <article> <p>Nihil morati ... </article> </section> <section> <article> <p>Post hanc ... </article> <article> <p>Et quoniam mirari ... </article> </section>

BODY comprend N sections.
Chaque section comprend N articles.

Nous voulons que les sections soient disposées selon l'axe vertical et les articles selon l'axe horizontal.

Le code CSS

body {display : flex; flex-direction : column;} section {display : flex ; flex-direction : row ; border : 2px solid black;} article {border : 1px solid black; } p{margin : 10px ; font-size : 14pt; text-align : left ; }

Le rendu

Observez le rendu !

Le centrage d'une boite flexible dans son conteneur

Vous savez qu'en CSS2 le centrage horizontal et vertical d'une boite dans son conteneur est une opération délicate.
Avec l'outil flexbox le centrage d'une boite dans son conteneur devient un jeu d'enfant.

Le code de l'exemple

... <style> #parent{ display : flex; flex-direction : column; justify-content : center ; align-items : center; border : 1px solid red; height : 600px;} #enfant {background : pink ; width : 60% ; } div p{margin : 10px ; font-size : 14pt; text-align : justify; } ... <body> ... <div id ="parent"> <div id ="enfant"> <p>Post hanc adclinis Libano monti Phoenice, ... </div> </div> ...

La propriété justify-content gère l'alignement selon l'axe principal et la propriété align-items gère l'alignement selon l'axe secondaire.
Donc pour centrer selon les deux axes il suffit que ces deux propriétés aient la valeur : center. Observez le rendu !

Gérer l'alignement

Revenons sur deux propriétés : justify-content et align-items.

Je rappelle que la propriété justify-content gère l'alignement selon l'axe principal et la propriété align-items gère l'alignement selon l'axe secondaire.

justify-content

align-items

Exemple

Le conteneur fait 600px de hauteur et les trois blocs flexibles doivent être disposés verticalement avec des marges identiques entre chaque bloc ainsi qu'aux extrémités.

La feuille de style :

#principale {display : flex; flex-direction : column ; justify-content : space-around; border :1px solid black; height:600px;} div#boite1 {background : lime ; } div#boite2 {background : pink ; } div#boite3 {background : coral ; } p{margin : 10px ; font-size : 14pt;}

Réduisez la largeur de l'onglet ; les marges se réduisent jusqu'à disparaitre. Le rendu !

Positionner une boite flexible dans un coin

Nous voulons qu'une boite soit positionnée en haut et à droite dans son conteneur.

Code CSS

#parent{ display : flex; flex-direction : column; justify-content : flex-start ; align-items : flex-end; border : 1px solid red; height : 600px ; } #enfant {background : pink ; width : 60% ; margin:10px ; } div p{margin : 10px ; font-size : 14pt; text-align : justify; }

Le Code HTML est identique à celui de l'exemple précédent ! Le rendu !

La boite flexible est bien positionnée en haut et à droite !
C'est parfaitement logique puisque l'axe principal est vertical (flex-direction : column) et que justify-content : flex-start alors que align-items : flex-end donc à la fin sur l'axe horizontal (axe secondaire ici).

Pour que la boite soit positionnée en bas et à gauche dans son conteneur ; quels règlages ?

Centrer plusieurs boites flexibles

Inutile de se prendre la tête !

Code CSS

...
	#parent{ display : flex;   flex-direction : column; justify-content : center ; align-items : center; 
			border : 1px solid red; height : 600px ; }
	.enfant {background : pink ; width : 80% ; margin :10px; } 

Code HTML

<div id ="parent"> <div class ="enfant"> <p>Post hanc adclinis Libano monti Phoenice, ... </div> <div class ="enfant"> <p>Post hanc adclinis Libano monti Phoenice, ... <p>Post hanc adclinis Libano monti Phoenice, ... </div> </div> ...

Les deux boites sont positionnées selon un axe vertical (flex-direction : column).
La hauteur de chaque boite est ajustée automatiquement en fonction du contenu et de la largeur imposée (80% de celle du conteneur).
Le rendu !

Astuce : les deux blocs ne se touchent pas grâce à la règle margin : 10px associée à la classe enfant.

Retour à la ligne

Problématique

Soit le code suivant (extrait) :

<style> #principale {display : flex; flex-direction : row ; border :1px solid black;} .enfant {width : 30%; margin :5px ; background : yellow;} ... <div id ="principale"> <div class ="enfant"> <p>Post hanc ... </div> ... <div class ="enfant"> <p>Nihil morati post ... </div> </div> ...

Le conteneur identifié "principale" contient 5 blocs de classe "enfant".
Chaque bloc a une largeur de 30% de celle du conteneur. Le rendu !

Il y a un gros problème : les boites "enfant" ne font pas 30% de large.
Pour que les 5 blocs tiennent sur un seul axe horizontal leur largeur a été automatiquement réduite.

Il faut forcer le retour à la ligne !

Solution

Concernant le code HTML aucun changement par contre au niveau de la feuille de style de nouvelles propriétés.

#principale {display : flex; flex-direction : row ; flex-wrap : wrap ; align-content : center; border :1px solid black;} .enfant {width : 30%; margin :5px; background : yellow;} Le rendu !

Les cinq blocs sont désormais sur deux axes horizontaux et font bien 30% de large.
Il y a centrage vertical des blocs dans le conteneur.

Pour créer un saut de ligne (ou saut de colonne) il faut ajouter : flex-wrap : wrap à flex-direction.
Dès que les blocs sont disposés sur plusieurs lignes (ou plusieurs colonnes) grâce à flex-wrap il faut alors utiliser la propriété align-content pour gérer la disposition des blocs.
Retour menu