grid et flex, leurs differences.
Ces dernieres années les modèles de boites utilisables se sont enrichis de deux type d'affichages en grilles: flex
et grid
.Vous en avez déjà probablement fait usage en reprenant des exemples qui fonctionnaient pour vos besoins. Voyons leurs différences et usages dans cet article.
Aux premiers abords et en les testant avec quelques elements, les résultats semblent similaires et peuvent preter à confusion dans leur usages et limites. Pourtant l'un ne fonctionne que sur un axe , portions par portions lorsque l'autre fonctionne sur les deux axes dans un tout, comme le ferait un tableau, ils sont en fait trés différents bien qu'ayant quelques propriétes apparement similaires.L'un etant plus flexible que l'autre posant un cadre.
Il s'agit là d'une belle évolution dans la panoplie des fonctions d'affichages disponibles via la propriété display
où flex
et grid
permettent de placer automatiquement dans une grille virtuelle leurs enfants directs.
Choses à savoir et à se rappeler à propos de leurs enfants directs
float
n'est pas applicable aux enfants direct. Les enfants sont des elements qui s'inscrivent dans une grille, determinant ainsi leur affichage et position.- Le sens de l'affichage du texte de la page est respecté, une mise en page basé sur l'un ou l'autre s'adapte automatiquement au sens d'écriture de la page.
- Pour les enfants directs,
display
(de typeinline
oublock
) n'ont plus d'incidences sauf pour leur contenu(ex:grid
/flex
/table
,..). - Margin permet de modifier leur alignement et peut modifier leur taille.
- Ils prennent par défaut la hauteur de leur ligne, cette hauteur est determiné par l'élement le plus haut. Si le sens d'affichage est modifié en colonnes (
flex-flow
,flex-direction
,grid-auto-flow
), c'est largeur du plus grand qui est determinante. - Des goutierres peuvent étre appliquées sans avoir recours aux marges.
- leur ordre d'affichage peut-être modifier sans modifier la position des enfants dans le code source.
Premieres différences importantes.
flex
crée une grille en une dimension, un seul axe est géré à la fois.
- Par défaut
flex
ne va créer qu'une seule ligne, conjointement avecflex-wrap:wrap
d'autres lignes pourront être generés au besoin. - flex ne permet pas de determiner les dimensions ou le nombre de cellules sur un axe de sa grille d'affichage, ce sont les enfants, eventuellement les dimensions qui leurs sont appliquées et l'espace disponibles qui determinera la grille d'affichage. Chaque ligne aura son affichage indépendant des autres. flex pour flexible.
flex
ne permet pas de positionner un elements sur plusieurs lignes ou colonnes à la fois.- la largeur de reference d'un enfant est celle du parent :
width:100%
= largeur de la boite parente enflex
grid
crée une grille en deux dimensions.
- Par défaut
grid
ne vas créer qu'une colonne et une nouvelle ligne sera généré pour chaque enfant.Plusieurs options sont disponibles pour initialisé votre grille :grid-area
,grid-template-rows
etgrid-template-columns
, par défault , la grille est calée surgrid-template-column:auto;
pour une seule colonne. grid
permet de créer une grille en donnant des positions et dimensions à ces cellules dans lesquelles les enfants se positionneront tour à tour en les remplissant.grid
permet d'afficher une cellule au travers d'une ou plusieurs colonnes, lignes, à la fois.- la largeur de reference d'un enfant est celle de sa cellule :
width:100%
= largeur de la cellule dans laquelle l'enfant se positionne. Cette largeur se regle à partir degrid-template-columns
de la grille.
Qu'ont ils en commun?
Il y a quelques propriétés communes:
justify-content
, règle l'alignement dans l'axe principalealign-items
, règle l'alignement dans l'axe opposé.gap
,definie les tailles des gouttieres verticales et horizontalesorder
permet de ré-attribuer une position dans le flux d'affichage aux enfants directs.- Tous deux peuvent aussi être formater comme des boites en ligne:
inline-flex
etinline-grid
. - tous deux peuvent être imbriquer et avoir des enfants en
display:flex
ougrid
. - Tous deux peuvent s'adapter aux differentes résolutions d'écran avec ou sans mediaqueries
@media
.
Il y a des comportement et des propriétes communes qui font que pour de simples grilles avec peu de contraintes, on pourrait dire que les deux permettront un résultat similaire., mais non, ces propriétés communes ne pourront pas toujours appliquer les mêmes régles de la même façon selon le contexte de la grille. Rappelez-vous que display:grid;
seul, ne construit qu'une colonne, Il est utile de connaitre ces deux-là et choisir le mieux adapté à votre projet.
Passons à quelques exemples de grilles, en flex
ou grid
.
3 colonnes sans contraintes.
Prenons cette structure HTML de 3 élements.
titre
paragraphe
...
La Version flex.
div.flex{
display:flex;
gap:2px;
}
div.flex > * {
border:solid 1px;
padding:0.5em;
flex-grow:1;
}
article {
width:70%;
}
nav a {
display:block;
}
Au niveau du parent, on declare le type d'affichage en flex
et la taille des gouttieres
Il n'y pas de grille explicite, celle-ci se forme à partir des enfants.
Les enfants heritent de 3 propriétés par défaut qui determine leur comportements: flex-grow:0;
flex-shrink:1;
flex-basis:auto;
Ces propriétés peuvent être ecrites en raccourcie regroupant les 3 : flex: 0 1 auto;
, ce qui signifie: ne s'agrandit pas dans l'espace disponible, peut retrecir et a une largeur automatique.
Dans l'exemple nous avons réinitialisé quelques valeurs:
flex-grow:1
pour que les enfants occupent et se partagent tout l'espace disponible.flex-basis:70%
pour donner une dimension à l'element en colonne centrale.
Par défaut flex-basis:70%
ou width:70%
peut-être automatiquement reduit afin d'eviter que la ligne depasse la largeur du parent. La valeur flex-shrink:1
appliquée par défaut autorise le retrécissement. en mettant la valeur à 0, ce n'est plus le cas.
En appliquant min-width:70%
l'element ne réduira pas sa largeur non plus.
Il se peut que vous ayez besoin de donner une largeur minimale qui ne corresponde pas à la largeur appliquée, par exemple flex-basis:70%; min-width:30em
sans toucher a flex-shrink
l'enfant pourra être reduit jusqu'a une largeur de 30em.
Vous pouvez construire votre grille flex en utilisant min-width
, width
et max-width
à partir des enfants sans réinitialiser les valeurs de flex. Un mélange permet des réglages plus subtiles sans avoir recours à @media
.
La Version grid.
div.grid{
display:grid;
gap:2px;
grid-template-columns: 1fr 70% 1fr;
}
div.grid > * {
border:solid 1px;
padding:0.5em;
}
nav a {
display:block;
}
C'est à partir du parent seul que le nombre et largeur de colonne est appliqué, ici via grid-template-columns
.
la hauteur des enfants se regle par defaut sur la cellule la plus haute de sa ligne comme pour une grille en flex.
3 colonnes + entête et pied sans contraintes.
Ajoutons un entête et pied de page à notre structure HTML.
Header
titre
paragraphe
...
La Version flex.
div.flex{
display:flex;
flex-wrap:wrap;
gap:2px;
}
div.flex > * {
border:solid 1px;
padding:0.5em;
flex-grow:1;
}
div.flex > header,
div.flex > footer {
flex-basis:100%;
}
article {
flex-basis:70%;
}
nav a {
display:block;
}
sur le parent, flex-wrap:wrap
est à ajouter pour pouvoir créer autant de ligne que necessaire
Pour que nos deux nouveau éléments prennent bien la largeur, flex-basis:100%
est aussi necessaire , mais maintenant width:100%
peut fonctionner mais si vous appliquer des marges a droite et gauche elles s'ajouteront aux 100% et provoqueront un débordement, flex-basis:100%
est à privilégier car il se chargera tout seul de calculer la largeur necessaire avec ou sans marges.
Remarque: flex-shrink
à maintenant des limites, si l'element devient trop petit pour son contenu, il passe maintenant à la ligne suivante afin d'eviter un débordement. flex est responsive.
La Version grid.
div.grid{
display:grid;
gap:2px;
grid-template-columns: 1fr 70% 1fr;
}
div.grid > * {
border:solid 1px;
padding:0.5em;
}
div.grid > header,
div.grid > footer {
grid-column:1 / -1;
}
nav a {
display:block;
}
La grille est toujours initialisée à partir du parent.
Les enfant peuvent se positionner dans plusieurs cellules. Pour traverser plusieurs colonnes , grid-column
permet de donner ces coordonnées : Ici : grid-column: 1 / -1
qui indique un placement de la premiere colonne jusqu'à la derniere.
Contrairement à l'exemple similaire précedent en flex, il y aura toujours ici 3 colonnes quelque soit la largeur de la page. Les contenus pourront facilement deborder. grid
pose une grille mais n'est pas flexible par défaut.
3 colonnes + entête et pied fullPage.
Affichons notre gabarit en pleine page avec la structure HTML précedente.
La Version flex.
div.flex{
display:flex;
flex-wrap:wrap;
gap:2px;
height:100vh;
}
div.flex > * {
border:solid 1px;
padding:0.5em;
flex-grow:1;
}
div.flex > header,
div.flex > footer {
flex-basis:100%;
}
article {
flex-basis:70%;
}
nav a {
display:block;
}
sur le parent, height:100vh est ajouter pour couvrir la hauteur de l'écran.
les lignes se partagent la hauteur de façon optimale, cependant la hauteur de l'entête et du pied de page peut paraitre trop importante
La Version grid.
div.grid{
display:grid;
gap:2px;
grid-template-columns: 1fr 70% 1fr;
height:100vh;
}
div.grid > * {
border:solid 1px;
padding:0.5em;
}
div.grid > header,
div.grid > footer {
grid-column:1 / -1;
}
nav a {
display:block;
}
La hauteur des lignes est ici partagée de la même façon.
tentons de reduire l'entete et pied de page à la juste hauteur necessaire.
La Version flex.
En consultant la panoplie des regles CSS utilisable dans une boite en flex, nous trouvons align-self
qui semble proche de notre besoin, essayons!
* {
margin:0;
padding:0
box-sizing:border-box;
}
div.flex{
display:flex;
flex-wrap:wrap;
gap:2px;
height:100vh;
}
div.flex > * {
border:solid 1px;
padding:0.5em;
flex-grow:1;
}
div.flex > header,
div.flex > footer {
flex-basis:100%;
height:max-content;
align-self: self-end;
}
div.flex > header {
align-self: self-start;
}
article {
flex-basis:70%;
align-self:stretch;
}
nav a {
display:block;
}
Les lignes sont indépendantes les unes des autres et si l'on peut gerer l'espace occuppé par un enfant dans l'axe principal d'affichage, il n'y aucun contrôle sur l'axe opposé. align-self
ne sera d'aucune utilité à part d'aligner l'element sur l'axe secondaire.
Solution partielle pour flex:
Une solution serait de modifier la structure HTML pour y imbriquer deux boites en flex, l'une construite en column et l'autre en ligne pour se servir de flex-grow
sur les deux axes que chaque boite dessine à l'écran.
* {
margin:0;
padding:0
box-sizing:border-box;
}
div.flex{
display:flex;
flex-direction:column;
gap:2px;
min-height:100vh;
}
main {
display:flex;
}
main,
main>nav,
main>aside {
flex-grow:1;
}
div.flex > header,
div.flex > footer,
div.flex main > *{
padding:0.5em;
border:solid 1px;
}
article {
flex-basis:70%;
}
nav a {
display:block;
}
Cette nouvelle construction fonctionne au prix d'une structure sur un niveau en plus et d'une réecriture des selecteurs et propriétés CSS. La base CSS précédente à du être refaite sans plus value.
Header
titre
paragraphe
paragraphe
Cette exemple repris est sans flex-wrap:wrap
, ce qui force à nouveau nav,article et aside à se presser les uns contre les autres, réinjecter flex-wrap:wrap;
sur main, réintroduit le passage à la ligne si besoin, mais aussi le partage de la hauteur des lignes que nous avons tenter de solutionner. Flex n'est plus le candidat idéal ici.
La Version grid.
div.grid{
display:grid;
gap:2px;
grid-template-columns: 1fr 70% 1fr;
grid-template-rows: auto 1fr auto;
height:100vh;
}
div.grid > * {
border:solid 1px;
padding:0.5em;
}
div.grid > header,
div.grid > footer {
grid-column:1 / -1;
}
nav a {
display:block;
}
La hauteur des lignes est ici gérable via grid-template-rows:
, pour que la ligne centrale occupe un maximum d'espace, il suffit de l'indiquer sur le parent.
Nous avons 3 lignes et la centrale doit occuper le plus grand espace possible, nous pouvons leur assigner un comportement . auto
sera pour l'entête et le pied et 1fr
pour la seconde ligne de la grille.
Il n'y a pas besoin de modifier la structure ni de récrire le CSS, il suffit d'ajouter grid-template-rows: auto 1fr auto;
aux régles que nous avons déjà sur la grille.
Ce n'est pas compliqué et notre grille et CSS de base ne demande qu'un point de réglage. La grille se configure aisément sans avoir recours à de nombreux selecteurs. C'est justement toute la force de ce mode d'affichage
Ceci est un parfait et pertinent exemple de l'usage de grid.
Le passage de 3 à 1 colonne
reprenons l'exemple en grid basé sur grille de 3x3 pour la repasser en une grille de 1 x 5. et voyons comment transposer une grille de 3 colonnes en une seule sur les petites résolutions
Pour le passage en une colonne, grid n'est plus necessaire, nous pouvons repasser en display:block;
pour aller au plus simple, cependant nous perdrons ces options:
- l'étalement du contenu sur toute la hauteur de la page
- les gouttieres
- l'ordre d'affichage
Les exemples précedents nous ont montré que flex
etait adapté pour un affichage sur un seul axe, transformons donc notre grille 2D construite avec grid
en une grille 1D à l'aide de flex
en créant un point de rupture pour basculer d'un mode à l'autre.
Pour l'exemple créons un point de rupture a 500px avec @media screen and (max-width: 500px ) {/*css */}
En passant au mode d'affichage en flex
, grid-template-rows
et grid-template-columns
deveviennent inapplicable mais flex-grow:1
pour l'element principal nous sera utile.
order
peut-etre mis à contribution pour remonter l'article juste sous l'entete et passer la navigation au dessous par exemple.
/* CSS du point de rupture à placer aprés les régles utiliser pour l'exemple en grid */
@media screen and (max-width: 500px ) {
div.grid {
display:flex;
flex-direction:column;
}
article {
flex-grow:1;
}
nav,
aside,
footer {
order:1;
}
nav a {
display: initial;
}
}
Pour voir l'exemple passer de 1 a 3 colonnes, modifier la largeur de votre navigateur de façon à déclancher le point de rupture dans l'exemple.
L'impossible en flex
grid
permet, comme les tableaux HTML, de positionner des cellules au travers de plusieurs lignes ou colonnes sans retoucher le code source.
Voici un exemple que flex ne pourra pas reproduire sans une modification du code source.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div.grid {
display: grid;
gap: 2px;
grid-template-columns:auto 70% auto;
grid-template-rows: auto 1fr auto;
height: 100vh;
}
div.grid > * {
border: solid 1px;
padding: 0.5em;
}
div.grid > header,
div.grid > footer {
grid-column: 2 / -1;
}
nav {
grid-row: 1 / -1;
}
nav a {
display: block;
}
@media screen and (max-width: 500px ) {
div.grid {
display:flex;
flex-direction:column;
}
article {
flex-grow:1;
}
nav a {
display: initial;
}
}
Pour un point de rupture dédié aux petits écrans, flex
reste utile pour reconstruire cette grille sur une seule colonne.
Vous l'aurez compris avec ces différents exemples, l'un ne remplace pas l'autre, display
est une belle trousse à outils complementaires.
Tous les examples sont télechargeable en fichier au format HTML
avec l'option de lui donner le nom que vous voulez .
Marché aux ressources:
- https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox
- https://la-cascade.io/css-grid-layout-guide-complet/
- https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout
- https://www.alsacreations.com/article/lire/1794-flexbox-ou-grid-layout.html