Comprendre CSS Grid : créer un container Grid
Dans cette nouvelle série, Rachel Andrew analyse la spécification CSS Grid Layout. Elle commence par ce qui se passe quand on crée un conteneur grid.
Nous commençons ici une nouvelle série d'articles consacrés à CSS Grid Layout, publiés dans Smashing Magazine. Grid est disponible depuis 2017, mais de nombreux développeurs n'ont pas encore eu l'occasion de l'utiliser dans le cadre d'un projet. A première vue, Grid vient avec toute une foule de propriétés et de valeurs, ce qui peut sembler rebutant. Mais en réalité, de nombreux détails de la spécification sont des variantes, ce qui signifie que vous n'avez pas besoin d'apprendre la spécification entière pour commencer. Cette série vise à vous faire passer de débutant à expert de Grid — et vous donnera de nombreux conseils pratiques en cours de route.
Dans ce premier article nous allons voir ce qui se passe lorsqu'on crée un grid container (conteneur de grille) et les diverses propriétés que vous pourrez utiliser sur l'élément parent pour contrôler cette grille. Vous découvrirez qu'il existe plusieurs cas d'utilisation qui ne sont réalisables qu'avec les propriétés de grid container. Dans cet article, nous couvrirons:
- Création d'un grid container avec display: grid ou display: inline-grid,
- Configuration des colonnes et des lignes avec grid-template-columns et grid-template-rows,
- Contrôle de la taille des pistes (tracks) implicites avec grid-auto-columns et grid-auto-rows.
NdT : les termes utilisés ici (pistes,...) sont des termes techniques qu'il faut connaître, nous renverrons à chaque fois que nécessaire vers le Guide Complet de CSS Grid Layout traduit ici.
Créer un container grid
Grid, comme Flexbox, est une valeur de la propriété display
. Par conséquent, pour indiquer au navigateur qu'on utilise la mise en page grid, on écrit display:grid
dans le css de l'élément. Le navigateur nous donne une boîte de niveau block sur l'élément en question et tout enfant direct sera inclus dans le contexte de formatage grid. Ils se comporteront comme des items grid et non comme des éléments block ou inline normaux.
Vous ne verrez sans doute aucune différence immédiate dans votre page à ce stade. Comme vous n'avez encore créé ni ligne ni colonne, vous avez une grille à une colonne. Suffisamment de rangées sont générées pour contenir tous les enfants directs et ils s'affichent l'un après l'autre dans cette colonne unique. Visuellement, ils ont l'air d'éléments block.
On verrait une différence si l'on avait à la fois une chaîne de caractères, non enveloppée dans un élément, et un enfant direct du container grid, du fait que cette chaîne de caractères serait enveloppée dans un élément anonyme et deviendrait un item grid. Tout élément normalement inline, comme un span
par exemple, devient un item grid dès lors que son parent est un container grid.
L'exemple qui suit montre deux éléments de niveau block et un texte contenant une span au milieu de la chaîne de caractères. On se retrouve avec cinq items grid :
- les deux éléments
div
- la chaîne de caractères qui précède le
span
- le
span
lui-même - la chaîne de caractères qui suit le
span
Si l'on inspecte la grille avec Firefox Grid Inspector, on voit les cinq rangées qui ont été crées pour nos items.
Il est possible de créer une grille inline avec display: inline-grid
; dans ce cas, notre container devient une boîte de niveau inline. Les enfants directs sont toujours des items grid et se comportent comme les items grid à l'intérieur d'une boîte de niveau block (c'est seulement le type d'affichage extérieur). C'est pourquoi le container grid se comporte de la même façon que précédemment quand il est avec avec d'autres boîtes dans une page.
L'exemple suivant montre une grille suivie d'une chaîne de caractères. Comme c'est une grille de niveau inline, le texte peut s'afficher à côté (les éléments de niveau inline ne s'étirent pas pour prendre toute la place dans la dimension inline, contrairement aux éléments de niveau block).
Note : à l'avenir, on pourra mieux décrire notre layout en utilisant display: block grid
pour créer un container de niveau block et display inline grid
pour créer un container de niveau inline.
Colonnes et rangées
Pour obtenir quelque chose qui ressemble à une grille, nous aurons besoin d'ajouter des colonnes et des rangées. Pour cela on utilise les propriétés grid-template-columns et grid-template-rows. Dans la spécification il est dit que ces propriétés acceptent une valeur appelée track-list
(une liste de pistes).
Ces propriétés spécifient, sous forme d'une liste de pistes séparées par un espace, les noms des lignes et les fonctions de dimensionnement des pistes de la grille. La propriété
grid-template-columns
spécifie la liste de pistes pour les colonnes de la grille, tandis quegrid-template-rows
le fait pour les rangées.
A titre d'illustration, voici quelques valeurs de listes de pistes possibles :
grid-template-columns: 100px 100px 200px;
crée une grille à trois colonnes: la première fait 100px de large, la deuxième aussi, la troisième fait 200px.grid-template-columns: min-content max-content fit-content(10em);
crée une grille à trois colonnes, la première à la taillemin-content
, la deuxième à la taillemax-content
. La troisième est à la taillemax-content
sauf si le contenu est plus grand que 10em, auquel cas il est limité à 10em.grid-template-columns: 1fr 1fr 1fr;
crée une grille à trois colonnes à l'aide de l'unitéfr
. L'espace disponible dans le container grid est divisé en trois et partagé entre les trois colonnes.grid-template-columns: repeat(2, 10em 1fr);
crée une grille de quatre colonnes selon un motif répété10em 1 fr 10em 1fr
, la liste de pistes étant répétée deux fois.grid-template-columns: repeat(autofill 200px);
remplit le container d'autant de colonnes de 200px que possible, et laisse un espace à la fin s'il reste de la place.grid-template-columns: repeat(autofill minmax(200px, 1fr));
remplit le container d'autant de colonnes de 200px que possible, puis distribue l'espace restant de manière égale entre les colonnes.grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end];
crée une grille de trois colonnes, la première et la troisième occupant une fraction de l'espace disponible et la troisième occupant trois fractions de l'espace disponible. Les lignes sont nommées en mettant leur nom entre crochets.
Comme vous pouvez le constater, il y a de nombreuses façons de créer une liste de pistes. Voyons maintenant comment tout cela fonctionne, en donnant quelques conseils d'utilisation.
Utilisation des unités de longueur
On peut utiliser n'importe quelle unité de longueur, ou un pourcentage, pour créer les pistes. Si la dimension des pistes est inférieure à l'espace disponible dans le container, alors par défaut les pistes s'aligneront au début du container et l'espace sera à la fin. Ceci, parce que la valeur par défaut de align-content
et de justify-content
est start
. On peut espacer les pistes, ou les déplacer vers la fin, en utilisant les propriétés d'alignement, comme je l'ai expliqué en détail dans Alignement en CSS, un guide complet
On peut aussi utiliser les mots-clés min-content
, max-content
et fit-content()
. Avec min-content
, on a une piste qui est aussi étroite que possible sans dépassement. Par conséquent, lorsqu'on l'utilise pour la largeur de la colonne, le contenu reviendra à la ligne à chaque fois que possible. La piste prend donc la dimension du mot le plus long de la colonne, ou du plus large élément de taille fixe.
Avec max-content
, c'est l'inverse, le contenu ne reviendra pas à la ligne du tout. Dans une colonne, cela peut donc avoir pour conséquence un texte qui déborde.
Le mot-clé fit-content()
quant à lui doit prendre une valeur, celle-ci devenant le maximum possible pour cette piste. La piste se comportera donc de la même façon que max-content
jusqu'à rencontrer la valeur spécifiée. Arrivé à ce point, le contenu pourra revenir à la ligne sans déborder. Autrement dit, votre piste peut être plus petite que la valeur spécifiée, mais jamais plus grande.
Vous trouverez plus d'information sur le dimensionnement dans Grid et d'autres méthodes de mise en page dans mon article CSS Flexbox et la dimension des boîtes.
Si vous avez des pistes qui prennent plus d'espace que disponible dans votre container, elles dépasseront. Si vous utilisez des pourcentages, vous devrez veiller à ce que le total ne soit pas supérieur à 100% pour éviter le dépassement.
L'unité fr
Grid Layout offre une méthode qui vous permettra d'éviter les calculs de pourcentages — le dimensionnement des pistes avec l'unité fr
. Cette unité n'est pas une longueur et par conséquent ne peut pas être utilisée en combinaison avec calc()
; c'est une unité flex qui représente l'espace disponible dans le container grid.
Autrement dit, avec une liste de pistes de 1fr 1fr 1fr
l'espace disponible est divisé en trois et partagé de façon égale entre les pistes. Avec une liste de pistes de 2fr 1fr 1fr
, l'espace disponible est divisé en quatre, deux parties sont données à la première piste et une partie à chacune des pistes deux et trois.
Un point auquel il faut être attentif est que ce qui est partagé par défaut, c'est l'espace disponible, qui n'est pas nécessairement l'espace total de notre container. Si une piste contient un élément de taille fixe ou un mot très long sans retour à la ligne, celle-ci sera mise en place avant le partage de l'espace restant.
Dans l'exemple qui suit, j'ai supprimé les espaces entre les mots de ItemThree
, ce qui crée une chaîne de caractères sans retour à la ligne possible. La distribution de l'espace se fait après que les conditions d'affichage de cet item aient été calculées.
On peut mélanger l'unité fr
avec des pistes de taille fixe et c'est d'ailleurs là qu'elle devient très utile. Par exemple on peut avoir un composant à deux colonnes fixes et une colonne centrale extensible :
On peut aussi avoir un composant avec une piste réglée sur fit-content(300px)
et l'autre sur 1fr
. On a ainsi un composant qui accepte quelque chose d'inférieur à 300px dans la première piste, auquel cas il prend seulement l'espace nécessaire, et l'unité fr
s'étend pour prendre le reste de l'espace disponible.
Si on ajoute quelque chose de plus grand (comme une image ayant une max-width: 100%
), la première piste sera limitée à 300px et l'unité fr
prendra le reste de l'espace. On crée des composant très flexibles en mélangeant l'unité fr
et fit-content()
.
La fonction repeat()
La function repeat() peut vous épargner la saisie de valeurs identiques. Les deux lignes ci-dessous sont équivalentes :
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(12, 1fr);
La valeur avant la virgule représente le nombre de répétitions, la valeur après la virgule représente la liste de pistes qui doit être répété. On peut avoir un seul pattern (comme ci-dessus) ou des valeurs multiples. Enfin, on peut utiliser repeat()
pour une partie d'une liste de pistes. Dans l'exemple ci-dessous, on aurait une piste 1fr
, trois pistes 200px
et une piste 1fr
pour finir.
grid-template-columns: 1fr repeat(3, 200px) 1fr;
A la place d'un nombre avant la virgule, indiquant un nombre fixe de répétitions d'un pattern, on peut utiliser les mots-clés auto-fill
ou auto-fit
. Le container grid sera rempli par autant de pistes qu'il peut en contenir.
L'utilisation d'une unité de mesure fixe a pour effet que si le container ne peut être divisé exactement par cette taille, il restera de l'espace disponible. Dans l'exemple ci-dessus, mon container fait 500px de large, et j'ai deux pistes de 200px et un espace vide à la fin.
Nous pouvons utiliser une autre fonction Grid pour transformer cette valeur fixe en minimum. La fonction minmax()
prend une taille minimum et une taille maximum. Avec un minimum de 200px et un maximum de 1fr, nous avons autant des pistes de 200px que le container peut accepter et comme le maximum est 1fr, ce qui, nous le savons, va répartir l'espace de façon égale, l'espace en trop sera distribué entre les pistes.
J'ai indiqué qu'il y avait deux mots-clés possibles : auto-fill
et auto-fit
. Si vous avez assez de contenu pour remplir la première rangée de cellules, celles-ci se comporteront exactement de la même manière. Si par contre vous n'avez pas assez de contenu (p.ex. si nous supprimons toutes les cellules sauf une dans le container précédent), alors elles se comporteront différemment.
auto-fill
maintiendra le dimensionnement de la piste, même s'il n'y a pas de contenu pour la remplir.
En revanche, si on utilise auto-fit
, les pistes vides seront fondues en une :
Firefox Grid inspector nous permet de voir que les pistes sont toujours là, mais qu'elles ont été fondues. La ligne finale de notre grille est toujours la ligne 3.
Lignes nommées
Mon exemple final ci-dessus utilisait l'approche des lignes nommées. Quand on utilise Grid, on a toujours des numéros de ligne, cependant, on peut aussi nommer les lignes. Leur nom apparaît entre crochets. On peut avoir plusieurs noms pour une ligne ; dans ce cas, un espace les sépare. Par exemple, dans la liste de pistes suivante, toutes mes lignes ont deux noms.
grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]
On peut nommer nos lignes comme on veut, sauf avec le mot span
qui est un mot réservé car il peut être utilisé pour placer des items dans la grille.
Note : dans les prochains articles de cette série, je parlerai plus en détails du placement basé sur les lignes et de la façon dont on peut se servir des lignes nommées. En attendant, vous pouvez lire mon article Naming Things in CSS Grid Layout (en anglais) pour en savoir plus sur le sujet.
Grille explicite vs grille implicite
Lorsqu'on crée une grille avec grid-template-columns
et grid-template-rows
et une liste de pistes, on crée ce qu'on appelle une grille explicite. C'est la grille que vous avez définie, avec le dimensionnement que vous avez choisi pour chaque piste.
Si vous avez plus d'items qu'elle n'en peut contenir, ou si vous placez un item de telle manière qu'il tombe en dehors des limites de la grille, Grid créera des pistes dans ce qu'on appelle la grille implicite. Ces pistes implicites seront autodimensionnées par défaut. Nous avons déjà vu cette grille implicite en action lorsque j'ai déclaré display: grid
dans l'élément parent et que grid a créé des rangées, une pour chaque item. Je n'avais pas défini ces rangées, mais puisqu'il y avait des items grid, les pistes de rangées ont été créées pour leur donner un endroit où aller.
On peut fixer une dimension pour les rangées ou colonnes implicites en utilisant les propriétés grid-auto-rows
ou grid-auto-columns
. Ces propriétés prennent une liste de pistes et si vous voulez que toutes les colonnes implicites aient ne hauteur d'au moins 200px mais qu'elles puissent s'agrandir s'il y a plus de contenu, vous pouvez écrire :
grid-auto-rows: minmax(200px, auto)
Si vous souhaitez que la première rangée implicite soit auto-dimensionnée et que la deuxième soit dimensionnée avec min-content
etc. (jusqu'à ce que tous les items grid soient en place), vous pouvez passer des valeurs multiples :
grid-auto-rows: auto 100px
Utiliser une grille avec placement automatique
Créer une grille (et permettre au navigateur de placer automatiquement les items) nous emmène loin en termes de patterns utiles. Nous n'avons pas encore abordé la question du placement des items dans la grille, mais de nombreuses mises en page réalisées avec Grid ne font aucun placement. Elle s'appuient simplement sur le placement d'items dans l'ordre de la source — un dans chaque cellule de la grille.
Si vous débutez avec CSS Grid, une bonne façon de comprendre comment ça marche est de s'amuser avec différentes dimensions de pistes, en regardant comment les items se placent dans les cellules.