Après plus de 15 ans de hacks et de polémiques sur la mise en page CSS, ne voilà-t-il pas qu'en 2018 le CSS Grid Layout Module est quasiment disponible dans tous les navigateurs majeurs.
Si vous aimez l'histoire et les détails, allez lire CSS Grid Layout is Here to Stay et The Story of CSS Grid, from Its Creators.
Si vous cherchez un bon tutoriel, celui de MDN est bien. Il commence aussi à y avoir pas mal d'articles.
Ci-dessous vous trouverez mes notes sur le sujet. Et autant dire que pour les vétérans de la mise en page CSS, les cartes sont rebattues. Il faut se débarrasser des réflexes acquis au fil des années. Bienvenue dans un nouveau monde.
Je me répète mais cette spécification est toujours en Candidate Recommendation à l'heure de la rédaction de ce billet. Et sous ce statut, les choses peuvent encore changer !
Terminologie
Un grid container définit un contexte de formatage grid pour son contenu. Ses enfants deviennent des grid items.
Voici les principaux termes utilisés dans la spécification :
- Grid line ou ligne de grille
- Grid track ou piste de grille : une séquence continue entre 2 lignes adjacentes, autrement dit l'espace entre deux lignes d'une grille
- Grid cell ou cellule de grille : un espace délimité par 4 lignes sans qu'aucune ligne ne passe à travers, la plus petite unité de la grille
- Grid area ou région de grille : n'importe quel espace délimité par 4 lignes et composé d'une ou plusieurs cellules de grille
Création d'une grille basique
On commence par réfléchir en termes de pistes. Il s'agit de spécifier la taille des pistes de chacun des deux axes d'une grille : les rangées et les colonnes.
Pour cela on utilise sur l'élément grid container les propriétés grid-template-rows
et grid-template-columns
:
#grid {
display: grid;
grid-template-columns: 200px 50% 100px;
grid-template-rows: 3em 80% 2em;
}
De cette définition de la taille des pistes découlent des lignes. Ces lignes sont numérotées automatiquement selon le sens de lecture du document en partant de 1 (pas de zéro). Il est possible de donner un ou plusieurs noms aux lignes de façon explicite :
#grid {
display: grid;
grid-template-columns: [start col-a] 200px [col-b] 50% [col-c] 100px [stop end last];
grid-template-rows: [start masthead] 3em [content] 80% [footer] 2em [stop end];
}
Création d'une grille avec des régions
On peut définir une grille de façon plus visuelle avec une syntaxe qui s'approche un peu de l'auto-documentation.
Pour cela on utilise sur l'élément grid container la propriété grid-template-areas
afin de créer des régions nommées. Sa syntaxe permet de visualiser la structure de la grille :
#grid {
display: grid;
grid-template-areas:
"header header header header"
"left content content right"
"left footer footer footer";
}
Des régions ainsi créées découlent des pistes. grid-template-areas
fonctionne donc de concert avec grid-template-columns
et grid-template-rows
pour dimensionner ces pistes. Il existe un raccourci grid-template
qui regroupe ces 3 propriétés.
Un point important à noter est que grid-template-areas
crée implicitement des noms pour certaines lignes. il s'agit des lignes de départ et de fin de chaque région qui sont nommées avec le nom de la région auquel on ajoute les suffixes -start
et -end
. Et ce sur chacun des 2 axes de la région. Sur la base de l'exemple ci-dessus, certaines lignes de la région header
qui s'étend sur 4 pistes obtiennent les noms implicites suivants :
- la ligne 1 verticale se nomme
header-start
- la ligne 5 verticale se nomme
header-end
- la ligne 1 horizontale se nomme
header-start
- la ligne 2 horizontale se nomme
header-end
Comme il est possible de donner plusieurs noms aux lignes, on peut toujours en ajouter des supplémentaires de façon explicite à l'aide des autres propriétés.
Positionner des éléments sur une grille
Pour positionner des éléments sur la grille, il faut réfléchir en termes de lignes. Pour cibler une ligne on se réfère à son numéro ou à son nom (implicite ou explicite).
On agit cette fois sur les éléments à placer eux-mêmes (les grid-items) en utilisant des propriétés qui servent à les attacher aux lignes de la grille :
grid-row-start
etgrid-row-end
pour placer un élément sur les lignes allant de haut en basgrid-column-start
etgrid-column-end
pour placer un élément sur les lignes allant de gauche à droitegrid-row
, raccourci pourgrid-row-start / grid-row-end
grid-column
, raccourci pourgrid-column-start / grid-column-end
grid-area
, raccourci pourgrid-row-start / grid-column-start / grid-row-end / grid-column-end
Les valeurs des propriétés raccourcies sont séparées par le caractère /
:
.one {
grid-column: 1 / 5;
grid-row: 1;
}
Quelques points intéressants :
- les valeurs non spécifiées des propriétés raccourcies sont définies à
auto
- il est possible de compter les lignes dans l'ordre inverse en utilisant des valeurs négatives ;
-1
désigne alors par exemple la première ligne disponible à droite pourgrid-column
et la première ligne en bas pourgrid-row
- il est possible d'utiliser le mot clé
span
pour spécifier combien de pistes de grille (grid tracks) doit occuper un élément de grille (grid-item) - l'ordre de
grid-area
esthaut / gauche / bas / droite
, ce qui est conflictuel avec l'ordre traditionnel comme celui depadding
qui esthaut / droite / bas / gauche
; c'est très bizarre…
Le raccourci grid-area
prend tout son sens quand le conteneur grille est déclaré avec des régions. Son fonctionnement rend les déclarations suivantes équivalentes :
grid-area: footer-start / footer-start / footer-end / footer-end;
grid-area: footer / footer / footer / footer;
grid-area: footer;
Du coup grid-area
permet de se référer à une région avec une syntaxe limpide :
#grid {
display: grid;
grid-template-areas:
"header header header header"
"nav main main main"
"nav footer footer footer";
}
#header { grid-area: header; }
#nav { grid-area: nav; }
#main { grid-area: main; }
#footer { grid-area: footer; }
On a l'impression de manipuler des régions alors qu'on touche toujours aux lignes.
Définir la taille des pistes avec l'unité fr
L'unité fr
représente une fraction de l'espace vacant dans un grid container et permet de créer des pistes de grilles flexibles. On l'utilise avec les propriétés grid-template-columns
et grid-template-rows
:
grid-template-columns: 1fr 1fr 1fr 1fr;
Pour déterminer la valeur d'un fr
, l'espace disponible du grid container est divisé par le nombre de fr
utilisés :
width: 100em;
grid-template-columns: 10em 4fr 3fr 20em;
=> 100em - 10em - 20em = 70em
70em / (4fr + 3fr) = 10
10em 40em (4fr * 10) 30em (3fr * 10) 20em
C'est très utile quand on a certaines colonnes qui doivent avoir une longueur fixe et d'autres qui doivent être flexibles.
C'est plus pratique d'utilisation que les %
car parfois des largeurs à 100% avec des marges supplémentaires génèrent un overflow.
L'expression repeat()
L'expression repeat()
permet de répéter un fragment des pistes d'une grille. On l'utilise avec les propriétés grid-template-columns
et grid-template-rows
:
/* Répéter 10 fois une colonne tous les 6 ems. */
#grid {
display: grid;
grid-template-columns: repeat(10, 6em);
}
/* Répéter 4 fois un même motif. */
#grid {
display: grid;
grid-template-columns: repeat(4, 1em 1fr 1fr);
}
/* Il est possible d'ajouter des valeurs avant ou après l'expression `repeat()`. */
#grid {
display: grid;
grid-template-columns: repeat(4, 1em 1fr 1fr) 2em;
}
Ajuster la taille des pistes en fonction du contenu
Il est possible de donner une taille à une piste en fonction de la taille intrinsèque de son contenu avec les valeurs min-content
ou max-content
pour les propriétés grid-template-columns
et grid-template-rows
. C'est utile quand par exemple on ne connaît pas d'avance la taille du contenu des grid items.
Ces valeurs sont décrites dans une autre spécification CSS (encore à l'état de Working Draft).
Elles permettent de définir une taille "idéale" en fonction du contenu.
min-content
obtiendra la même taille que l'élément dont la taille intrinsèque est la plus petite au delà de laquelle il n'est plus possible de réduire la taille sans couper ou masquer cet élément.
max-content
obtiendra la même taille que l'élément dont la taille intrinsèque est la plus grande.
C'est plus parlant avec un exemple.
La fonction minmax(min, max)
Cette fonction permet de définir une taille de piste en incluant une valeur minimale et une valeur maximale. On l'utilise avec les propriétés grid-template-columns
et grid-template-rows
.
Je vous conseille d'aller lire How the minmax() Function Works pour comprendre comment elle fonctionne.
Il faut noter que l'unité fr
n'est pas autorisée en tant que valeur min
de minmax(min, max)
.
Pour aller plus loin
Je m'arrête là pour le moment mais il me reste pas mal de points à creuser :
fit-content
- la grille implicite
grid-auto-rows
etgrid-auto-columns
auto-fill
etauto-fit
grid-auto-flow
- l'alignement sur les axes d'une grille
- le raccourci
grid
- les gouttière avec
gap
,column-gap
etrow-gap
Mais ça sera pour une autre fois :)