-
CSS > grid
- Démarrer avec un document structuré et accessible
- Une disposition en grille ne doit pas nécessiter de changement dans la structure du document pour obtenir la disposition souhaitée. Aussi, pour commencer, le document qui forme la page doit être bien structuré et accessible. Comme indiqué dans la spécification, cette structure de base doit également fournir une bonne structure pour les petits écrans. Si un utilisateur fait défiler le site sur un appareil mobile, les éléments qu’il doit voir en premier sont généralement ceux qui sont au début du document dans la source.
- Créer une grille adaptative correcte
- Grâce à cette structure de base claire, on peut complexifier la disposition. Il est probable qu’on veuille ajouter des requêtes de média afin de créer des colonnes supplémentaires et gérer différentes tailles d’écran et différents appareils. Une grille peut s’avérer très utile pour déplacer les éléments qui étaient moins prioritaires sur mobile afin de construire la disposition d’un écran plus large. Une bonne stratégie consiste à tester chaque disposition, simplement en utilisant la navigation avec la touche tabulation : est-ce que cet ordre est pertinent ? est-ce qu’on ne passe pas d’un coup du haut en bas de la page ?
- Revenir à la source
- Si, pendant cette phase de conception, vous avez besoin de replacer un élément avec la grille, analysez s’il est nécessaire de replacer cet élément dans l’ordre logique du document. Les grilles CSS ont cela de pratique qu’elles permettent de déplacer un élément dans le document source sans qu’il soit nécessaire de modifier profondément les règles de style. C’est un atout considérable par rapport aux dispositions construites avec float où la structure et l’ordre du document jouaient un rôle fondamental. Cela demande toutefois de garder à l’esprit qu’il faut revenir à la source pour mettre à jour et maintenir l’ordre logique.
CSS Grid cheatsheet
Container
.grid-container { display: grid; /* Columns and rows */ grid-template-columns: 1rem auto 25% 2fr; /* Fill remaining widths with auto or fr units */ grid-template-columns: repeat(12, 1fr); /* Repeat columns without needing to write them */ grid-template-rows: 1rem 10% auto repeat(5, 10px); /* Automatic columns and rows */ grid-auto-columns: 10px; /* No matter how many columns of content end up in the grid, each column will be this same width */ grid-auto-rows: 1rem; /* No matter how many rows of content end up in the grid, each row will be this same height */ /* Areas */ grid-template-areas: "header header" "main aside" "footer footer"; /* Template shorthand */ grid-template: "header header" auto "main aside" 100vh "footer footer" 10rem / 80% 20%; /* The above is the same as below long-hand */ grid-template-columns: 80% 20%; grid-template-rows: auto 100vh 10rem; grid-template-areas: "header header" "main aside" "footer footer"; /* Gaps */ grid-row-gap: 1rem; grid-column-gap: 0.5rem; /* Define values separately */ grid-gap: 1rem 0.5rem; /* Short-hand for row / column */ grid-gap: 1rem; /* Gap in both dimensions */ /* Item justification (horizontal or column alignment) */ justify-items: start; /* Align items to the left */ justify-items: center; /* Align items centered within its column */ justify-items: end; /* Align items to the right */ justify-items: stretch; /* (default) Fills available area (horizontally) */ /* Item alignment (vertical or row alignment) */ align-items: start; /* Align items to the top */ align-items: center; /* Align items centered within its row */ align-items: end; /* Align items to the bottom */ align-items: stretch; /* (default) Fills available area (vertically) */ /* Place item shorthand */ place-items: start stretch; /* The above is the same as below long-hand */ align-items: start; justify-items: stretch; /* Content justification (horizontal or column alignment) */ justify-content: start; /* Align content to the left */ justify-content: center; /* Align content centered horizontally within the grid */ justify-content: end; /* Align content to the right */ justify-content: stretch; /* (default) Fills available area (horizontally) */ justify-content: space-around; /* Chooses a space for both sides of the columns like a left and right margin */ justify-content: space-between; /* Chooses a space to go between columns, no margins on outside of content */ justify-content: space-evenly; /* Chooses a space that goes between all columns and edges consistently */ /* Content alignment (horizontal or column alignment) */ align-content: start; /* Align content to the top */ align-content: center; /* Align content centered vertically within the grid */ align-content: end; /* Align content to the bottom */ align-content: stretch; /* (default) Fills available area (vertically) */ align-content: space-around; /* Chooses a space for the top and bottom of the rows like a top and bottom margin */ align-content: space-between; /* Chooses a space to go between rows, no margins on outside of content */ align-content: space-evenly; /* Chooses a space that goes between all rows and edges consistently */ /* Place item shorthand */ place-content: center start; /* The above is the same as below long-hand */ align-content: center; justify-content: start; /* Automatic grid positioning */ grid-auto-flow: row; /* Left-to-right rows, then top-to-bottom*/ grid-auto-flow: column; /* Top-to-bottom columns, then left-to-right */ grid-auto-flow: dense; /* Responds with best-guess on left-to-right, top-to-bottom order with advanced layouts */ /* There is one final shorthand for all container properties in one */ /* Explicit grid columns, rows, and areas */ grid: "header header" auto "main aside" 100vh "footer footer" 10rem / 80% 20%; /* You can include a template as the only value, which is equivalent to below */ grid-template: "header header" auto "main aside" 100vh "footer footer" 10rem / 80% 20%; /* Which is again equivalent to below */ grid-template-columns: 80% 20%; grid-template-rows: auto 100vh 10rem; grid-template-areas: "header header" "main aside" "footer footer"; /* Automatic grid flows */ grid: 1rem / auto-flow dense 1fr; /* You can include rows, a flow, and automatic columns, which is equivalent to below */ grid-template-rows: 1rem; grid-auto-flow: dense; grid-auto-columns: 1fr; grid: auto-flow dense 1rem / repeat(10, 10%); /* Conversely, you can do the same thing with automatic rows, and defined columns */ grid-auto-flow: dense; grid-auto-rows: 1rem; grid-template-columns: repeat(10, 10%); }
Child
.grid-child { /* Column position */ grid-column-start: 1; grid-column-end: 2; grid-column: 1 / 2; /* Short hand */ grid-column: 1 / span 2; /* Span 2 columns without explicitly defining an endpoint */ grid-column: 1; /* Start in and occupy a single column */ /* Row position */ grid-row-start: 2; grid-row-end: 4; grid-row: 2 / 4; /* Short hand */ grid-row: 2 / span 3;/* Span 3 rows without explicitly defining an endpoint */ grid-row: 1; /* Start in and occupy a single row */ /* Area positioning */ grid-area: header; /* You can use a named grid area from the container */ grid-area: 2 / 1 / 4 / 2; /* Or you can use positioning. This is equivalent to... */ grid-row-start: 2; grid-column-start: 1; grid-row-end: 4; grid-column-end: 2; /* Self justification (horizontal or column alignment) */ justify-self: start; /* Align item to the left */ justify-self: center; /* Align item centered within its column */ justify-self: end; /* Align item to the right */ justify-self: stretch; /* (default) Fills available area (horizontally) */ /* Self alignment (vertical or row alignment) */ align-self: start; /* Align item to the top */ align-self: center; /* Align item centered within its row */ align-self: end; /* Align item to the bottom */ align-self: stretch; /* (default) Fills available area (vertically) */ /* Placement shorthand */ place-self: start stretch; /* The above is the same as below long-hand */ align-self: start; justify-self: stretch; }
#References
GRID: A simple visual cheatsheet
CSS Tricks: A Complete Guide to Grid
—
Les concepts de base des grilles CSS
Le conteneur
On crée un conteneur en déclarant la propriété display: grid ou display: inline-grid sur un élément, tous les enfants directs de cet élément deviennent des éléments de grille. Par défaut, grid n’a qu’une seule colonne.
Les pistes
grid-template-columns et grid-template-rows permettent de définir des colonnes et des rangées. Celles-ci définissent les pistes. Une piste est l’espace entre deux lignes d’une grille et correspondant à une rangée.
On peut ajouter la propriété grid-template-columns à notre exemple précédent, pour définir la taille des colonnes.
Nous avons créé une grille avec trois pistes de 200 pixels de large. Chaque élément sera disposé dans l’une des cellules de la grille.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: 200px 200px 200px; }
L’unité fr
Les pistes peuvent être définies à l’aide de n’importe quelle unité de mesure. Les grilles proposent aussi une nouvelle unité de mesure pour aider à la création de pistes flexibles. Cette unité, fr, représente une fraction de l’espace disponible dans le conteneur de la grille. Le code suivant crée trois colonnes égales qui se redimensionnent en fonction de l’espace disponible.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; }
L’exemple suivant crée une grille avec une colonne de 2fr, et deux colonnes de 1fr. L’espace disponible est divisé en quatre. Les deux premières fractions sont allouées à la première colonne, et chacune des colonnes suivante dispose d’une fraction.
.wrapper { display: grid; grid-template-columns: 2fr 1fr 1fr; }
Dans ce dernier exemple nous utilisons à la fois des dimensions absolues et des relatives. La première colonne faisant 500px, cette valeur est soustraite de l’espace disponible. L’espace restant est divisé en trois et alloué proportionnellement aux deux colonnes spécifiées avec l’unité relative fr.
.wrapper { display: grid; grid-template-columns: 500px 1fr 2fr; }
Utiliser la notation repeat() pour définir les pistes
Pour les grilles comprenant de nombreuses pistes on peut utiliser la notation repeat() pour répéter toute ou une partie des pistes définies. Par exemple la définition de grille :
.wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; }
peut également s’écrire :
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); }
Dans l’exemple suivant on crée une grille avec une première colonne de 20px de large, puis une section répétant 6 fois une piste de 1fr, et enfin on termine par une colonne de 20px de large.
.wrapper { display: grid; grid-template-columns: 20px repeat(6, 1fr) 20px; }
Cette notation accepte une liste de pistes, on peut donc l’utiliser pour répéter un motif. Dans l’exemple qui suit la grille aura 10 colonnes : une colonne de 1fr suivie d’une colonne de 2fr, ceci répété 5 fois.
.wrapper { display: grid; grid-template-columns: repeat(5, 1fr 2fr); }
Grille implicite et grille explicite
Dans ces exemples nous avons défini nos colonnes à l’aide de la propriété grid-template-columns, et nous avons laissé la grille créer les rangées. Ces rangées font partie de la grille implicite.La grille explicite est constituée des pistes définies par les propriétés grid-template-columns et grid-template-rows. Si un élément est placé en dehors de la grille ainsi définie, ou que la quantité de contenu nécessite d’étendre la grille, alors la grille ajoute implicitement des colonnes et rangées. Les dimensions de ces pistes auront par défaut la valeur auto, c’est-à dire qu’elles s’ajusteront à leur contenu.
On peut définir une taille pour les pistes de la grille implicite grâce aux propriéts grid-auto-rows et grid-auto-columns.
Dans l’exemple ci-après nous utilisons grid-auto-rows pour que les rangées de la grille implicite fassent 200 pixels de haut.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 200px; }
Dimensionner une piste avec minmax
Que l’on crée une grille explicite, ou que l’on définisse la taille des pistes créées implicitement, il peut être utile d’assigner une taille minimum, qui s’agrandit pour s’adapter au contenu. Par exemple on peut souhaiter que les rangées ne soient jamais moins hautes que 100 pixels, mais qu’elles aillent jusqu’à 300 pixels de haut si le contenu le nécessite.
La fonction minmax() permet ce comportement. Dans l’exemple suivant nous utilisons minmax() comme valeur de la propriété grid-auto-rows. Les rangées créées automatiquement feront un minimum de 100 pixels, et un maximum de auto, ce qui signifie que la taille s’adaptera à la hauteur du contenu.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(100px, auto); }
<div class="wrapper"> <div>Un</div> <div>Deux <p>Davantage de contenu.</p> <p>On dépasse les 100 pixels.</p> </div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
Lignes de grille
Il faut noter que l’on définit les pistes d’une grille, et pas les lignes qui en résultent. La grille génère des lignes numérotées que l’on utilise pour positionner les éléments. Dans notre grille de trois colonnes et deux rangées, nous avons quatre lignes de colonnes.
Les lignes sont numérotées selon le sens de lecture du document. Dans un langage qui se lit de gauche à droite, la ligne 1 est située à gauche, dans un langage qui se lit de droite à gauche elle est située à droite. Les lignes peuvent aussi être nommées, comme nous le verrons plus loin dans ces pages.
Positionnement des éléments sur les lignes
Nous explorerons le placement sur les lignes plus en détail dans un prochain article, l’exemple qui suit montre comment l’utiliser de façon simple.
Lorsque nous plaçons un élément nous ciblons une ligne plutôt qu’une piste. Nous plaçons ici les deux premiers éléments en utilisant les propriétés grid-column-start, grid-column-end, grid-row-start et grid-row-end. En allant de gauche à droite, le premier élément est placé sur la ligne de colonne 1, et va jusqu’à la ligne de colonne 4, qui dans ce cas est la dernière. Il est placé sur la ligne de rangée 1, et va jusqu’à la ligne 3, s’étendant ainsi sur deux rangées.
Le second élément commence sur la ligne de colonne 1 et s’étend sur une seule piste. C’est la largeur par défaut, donc il n’est pas nécessaire de spécifier la ligne de fin. Il s’étend aussi sur deux rangées de la ligne 3 à la ligne 5. Les autres éléments se placeront dans les espaces vides de la grille.
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> <div class="box5">Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; } .box1 { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; } .box2 { grid-column-start: 1; grid-row-start: 3; grid-row-end: 5; }
Pensez à utiliser l’Inspecteur de grille dans les outils de développement pour voir comment les éléments se placent sur les lignes d’une grille items.
Les cellules
Une cellule est la plus petite unité sur une grille, conceptuellement similaire à une cellule de tableau. Comme nous l’avons vu lorsqu’une grille est définie sur un élément ses enfants viennent se positionner chacun dans l’une des cellules de la grille. Dans l’image ci-dessous la première cellule est colorée.
Les zones
Un élément peut s’étendre sur plusieurs cellules d’une rangée ou d’une colonne, et cela crée une zone. Les zones doivent être rectangulaires - on ne peut pas créer de forme en L par exemple. La zone colorée ci-dessous s’étend sur deux rangées et deux colonnes.
Les gouttières
Les gouttières entre les cellules sont définies à l’aide des propriétés grid-column-gap et row-gap, ou de la propriété raccourcie gap. Dans l’exemple ci-dessous nous créons une gouttière de dix pixels de large entre les colonnes, et une gouttière de 1em de hauteur entre les rangées.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-column-gap: 10px; grid-row-gap: 1em; }
Note : Les anciens navigateurs utilisent column-gap, row-gap, gap avec le préfixe grid- soit : grid-column-gap, row-gap et gap.
Les navigateurs actuels retirent progressivement ce préfixe (la version préfixée sera maintenue sous forme d’alias). À l’heure actuelle, certains navigateurs ne prennent pas encore la version sans préfixe et c’est pourquoi certains exemples de ce guide continuent d’utiliser les versions préfixées avec grid-.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
L’espace utilisé par les gouttières sera pris en compte avant l’assignation de la place restante aux pistes définies avec l’unité fr. La taille des gouttières est calculée comme celle des pistes, mais on ne peut pas placer d’élément dans une gouttière. Au niveau du positionnement des éléments sur les lignes, la gouttière se comporte comme une ligne épaisse.
Grilles imbriquées
Un élément placé dans une grille peut aussi être le conteneur d’une autre grille. Dans l’exemple suivant nous retrouvons la grille de trois colonnes créée plus haut, avec deux éléments explicitement positionnés. Le premier élément contient lui-même des éléments. Comme ils ne sont pas des enfants directs de la grille principale, ils se positionnent normalement dans le flux.
<div class="wrapper"> <div class="box box1"> <div class="nested">a</div> <div class="nested">b</div> <div class="nested">c</div> </div> <div class="box box2">Deux</div> <div class="box box3">Trois</div> <div class="box box4">Quatre</div> <div class="box box5">Cinq</div> </div>
En définissant la propriété display:grid sur l’élément box1, il devient lui-même une grille et ses enfants se positionnent sur cette grille.
.box1 { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; display: grid; grid-template-columns: repeat(3, 1fr); }
Dans ce cas la grille imbriquée n’est pas liée à la grille qui la contient. Elle n’hérite pas des gap, et ses lignes ne s’alignent pas avec celles de la grille parent.
Sous-grille
Dans le brouillon de travaille pour la spécification de niveau 2 pour CSS Grid, il existe une fonctionnalité nommée sous-grille qui permet de créer des grilles imbriquées qui utilisent la définition de la grille parent. Ceci n’est implémenté dans aucun navigateur pour le moment, et la spécification peut encore changer. Pour l’utiliser telle qu’elle est définie actuellement il faudrait modifier l’exemple suivant et remplacer display: grid par display: subgrid, et supprimer la définition des pistes. La piste imbriquée utiliserait les pistes de la grille parent pour positionner ses éléments.
Selon la version actuelle de la spécifiction, il faudrait éditer l’exemple de grille imbriquée précédent et remplacer grid-template-columns: repeat(3, 1fr) en grid-template-columns: subgrid. La grille imbriquée utilisera alors la grille parente pour inscrire ses éléments dans le document.
.box1 { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; display: grid; grid-template-columns: subgrid; }
Superposer les éléments avec z-index
Plusieurs éléments peuvent être placés dans la même cellule. Si nous retournons à notre exemple avec les items positionnés par numéros de ligne, nous pouvons modifier cela pour que deux items se chevauchent.
<div class="wrapper"> <div class="box box1">Un</div> <div class="box box2">Deux</div> <div class="box box3">Trois</div> <div class="box box4">Quatre</div> <div class="box box5">Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; } .box1 { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; } .box2 { grid-column-start: 1; grid-row-start: 2; grid-row-end: 4; }
L’élément box2 est maintenant superposé avec box1, et comme il arrive après dans le code source il s’affiche par-dessus.
Contrôler l’ordre de superposition
On peut contrôler l’ordre dans lequel les éléments s’empilent en utilisant la propriété z-index. Si nous donnons à box2 un z-index inférieur à celui de box1, l’élément box2 s’affichera sous box1 dans la pile.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; } .box1 { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; z-index: 2; } .box2 { grid-column-start: 1; grid-row-start: 2; grid-row-end: 4; z-index: 1; }
La suite
Dans cet article nous avons parcouru rapidement la spécification CSS Grid Layout. Essayez de jouer avec les exemples, avant de passer aux parties suivantes de ce guide pour commencer à vraiment plonger dans le détail de la CSS Grid Layout.
—
Placer les éléments sur les lignes d’une grille CSS
Dans l’article sur les concepts de base, nous avons vu comment positionner des éléments en utilisant des numéros de lignes. Nous allons désormais étudier cette fonctionnalité de positionnement plus en détail.
Commencer par utiliser les lignes numérotées est plutôt logique car toutes les grilles possèdent des lignes numérotées. Ces lignes forment les colonnes et les lignes horizontales de la grille, elles sont numérotées à partir de 1. On notera aussi que la numérotation des lignes varie selon le mode d’écriture du document. Dans un document écrit de gauche à droite comme le français, la ligne numéro 1 est située à l’extrêmité gauche de la grille. Si l’écriture va de droite à gauche, la ligne numéro 1 sera celle qui est située le plus à droite. Nous explorerons ces notions sur les modes d’écriture dans un prochain guide.
Un exemple simple
Dans cet exemple simple, on a une grille avec trois pistes pour les colonnes et trois pistes pour les lignes, on a donc 4 lignes pour chaque dimension.
Dans le conteneur, on a quatre éléments fils. Si aucune autre règle de placement n’est indiquée, ces éléments seront placés automatiquement et la grille remplira les quatre premières cellules. Si vous utilisez l’outil de mise en évidence des grilles de Firefox, vous pouvez voir les colonnes et les lignes horizontales formées par la grille.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 100px); }
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
Positionner les éléments d’une grille grâce au numéro de ligne
On peut placer les éléments d’une grille en utilisant les numéros de lignes qui définissent la zone allouée à l’élément. Si on souhaite que le premier élément commence tout à gauche et occupe une colonne, qu’il commence sur la première ligne et s’étale sur quatre lignes, on pourra utiliser les règles suivantes :
.box1 { grid-column-start: 1; grid-column-end: 2; grid-row-start: 1; grid-row-end: 4; }
Lorsqu’on positionne des objets sur la grille, les autres continueront d’être placés selon les règles de placement automatique. Nous verrons ces règles dans un prochain guide mais grâce à cet exemple, on peut voir que les cellules vides sont remplies au fur et à mesure par les objets qui ne sont pas placés explicitement.
On peut placer chacun des éléments individuellement et on peut également choisir de laisser certaines cellules vides. Un des avantages de la grille CSS est qu’on peut créer des espaces sans avoir à utiliser des marges ou d’autres méthodes de contournement.
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
.box2 { grid-column-start: 3; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3; } .box3 { grid-column-start: 2; grid-column-end: 3; grid-row-start: 1; grid-row-end: 2; } .box4 { grid-column-start: 2; grid-column-end: 4; grid-row-start: 3; grid-row-end: 4; }
Les propriétés raccourcies grid-column et grid-row
On a écrit beaucoup de règles pour positionner chaque élément. Heureusement, il existe des propriétés raccourcies qui permettent d’avoir une syntaxe plus concise. Les propriétés grid-column-start et grid-column-end peuvent être combinées pour former la propriété raccourcie grid-column et de la même façon, grid-row-start et grid-row-end peuvent être synthétisées avec grid-row.
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
.box1 { grid-column: 1 / 2; grid-row: 1 / 4; } .box2 { grid-column: 3 / 4; grid-row: 1 / 3; } .box3 { grid-column: 2 / 3; grid-row: 1 / 2; } .box4 { grid-column: 2 / 4; grid-row: 3 / 4; }
La taille par défaut
Dans les exemples précédents, on a défini chaque ligne et colonne de fin pour chaque élément. Mais si en pratique, on souhaite qu’un élément n’occupe qu’une seule piste, on peut omettre grid-column-end ou grid-row-end. Par défaut, les éléments occupent une seule piste. Notre exemple initial, avec les propriétés détaillées peut donc être réécrit de cette façon :
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
.box1 { grid-column-start: 1; grid-row-start: 1; grid-row-end: 4; } .box2 { grid-column-start: 3; grid-row-start: 1; grid-row-end: 3; } .box3 { grid-column-start: 2; grid-row-start: 1; } .box4 { grid-column-start: 2; grid-column-end: 4; grid-row-start: 3; }
Tailles par défaut avec les propriétés raccourcies
Avec les propriétés raccourcies, on obtient le code suivant (sans aucune barre oblique ni seconde valeur pour les éléments qui n’occupent qu’une seule piste).
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
.box1 { grid-column: 1 ; grid-row: 1 / 4; } .box2 { grid-column: 3 ; grid-row: 1 / 3; } .box3 { grid-column: 2 ; grid-row: 1 ; } .box4 { grid-column: 2 / 4; grid-row: 3 ; }
La propriété grid-area
On peut aller plus loin et définir une zone pour chaque élément grâce à une seule propriété : grid-area. Cette propriété raccourcie permet d’utiliser les valeurs des propriétés suivantes (dans cet ordre) :
grid-row-start
grid-column-start
grid-row-end
grid-column-end
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
.box1 { grid-area: 1 / 1 / 4 / 2; } .box2 { grid-area: 1 / 3 / 3 / 4; } .box3 { grid-area: 1 / 2 / 2 / 3; } .box4 { grid-area: 3 / 2 / 4 / 4; }
L’ordre des valeurs utilisé pour grid-area peut sembler un peu étrange quand on connaît celui utilisé par les propriétés raccourcies pour les marges (margin) et le remplissage (padding). Cet ordre s’explique car les grilles CSS fonctionnent avec les différents modes d’écriture et on utilise des propriétés et des valeurs logiques plutôt que des propriétés et des valeurs physiques. Nous aborderons ce point dans un prochain article mais il faut retenir ici que l’ordre des valeurs correspond aux directions logiques suivantes :
block-start
block-end
inline-start
inline-end
On travaille ici en anglais ou en français, une langue qui s’écrit de gauche à droite. La ligne physique correspondant à la ligne logique block-start est donc la ligne en haut du conteneur, block-end correspond à la ligne en bas du conteneur, inline-start correspond à la colonne la plus à gauche (le point de départ de l’écriture pour une ligne) et inline-end correspond à la dernière colonne, celle qui est située à l’extrémité droite de la grille.
Lorsqu’on définit une zone d’une grille grâce à la propriété grid-area, on commence par définir les lignes de « début » : block-start et inline-start puis les lignes de « fin » avec block-end et inline-end. Cela peut paraître étrange quand on est habitué à manipuler des propriétés physiques qui progressent dans le sens horaire : haut, droit, bas, gauche mais cet ordre paraît plus pertinent quand on considère que les sites web peuvent être multi-directionnels selon le mode d’écriture.
Compter à rebours
Pour faire référence à la dernière ligne, on utilise -1 et compter à rebours au fur et à mesure ( -2 l’avant-dernière ligne). Attention, Ce comptage ne prend pas en compte les lignes ou les colonnes qui sont ajoutées implicitement dans la grille.
Dans le prochain exemple, on renverse la disposition de la grille en travaillant à partir du bas et de la droite.
.box1 { grid-column-start: -1; grid-column-end: -2; grid-row-start: -1; grid-row-end: -4; } .box2 { grid-column-start: -3; grid-column-end: -4; grid-row-start: -1; grid-row-end: -3; } .box3 { grid-column-start: -2; grid-column-end: -3; grid-row-start: -1; grid-row-end: -2; } .box4 { grid-column-start: -2; grid-column-end: -4; grid-row-start: -3; grid-row-end: -4; }
Étirer un élément sur la grille
Étant donné qu’on peut utiliser les numéros de lignes pour la première et la dernière, on peut facilement étirer un élément pour que celui-ci occupe toute la largeur et/ou toute la hauteur de la grille avec :
.item { grid-column: 1 / -1; }
Les gouttières
.box1 { grid-column: 1 ; grid-row: 1 / 4; } .box2 { grid-column: 3 ; grid-row: 1 / 3; } .box3 { grid-column: 2 ; grid-row: 1 ; } .box4 { grid-column: 2 / 4; grid-row: 3 ; } .wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 100px); grid-column-gap: 20px; grid-row-gap: 1em; }
Les propriétés raccourcies pour les gouttières
Les deux propriétés que nous venons de voir peuvent être synthétisées grâce à la propriété raccourcie gap. Si on fournit une seule valeur, celle-ci s’appliquera pour les espaces entre les colonnes et entre les lignes. Avec deux valeurs, la première sera utilisée pour grid-row-gap et la seconde pour grid-column-gap.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 100px); grid-gap: 1em 20px; }
Par rapport au positionnement sur les lignes, les gouttières agissent comme si la ligne avait gagné en largeur ou en hauteur. Tout ce qui commence sur une ligne commencera après cet espace et on ne peut placer aucun élément dans cette gouttière. Aussi, si on veut qu’une gouttière agisse comme une piste classique dans laquelle on peut placer des objets, il suffira de définir une nouvelle piste plutôt qu’une gouttière.
span
.box1 { grid-column: 1; grid-row: 1 / span 3; } .box2 { grid-column: 3; grid-row: 1 / span 2; } .box3 { grid-column: 2; grid-row: 1; } .box4 { grid-column: 2 / span 2; grid-row: 3; }
Le mot-clé span peut également être utilisé dans les valeurs des propriétés grid-row-start/grid-row-end et grid-column-start/grid-column-end. Les deux fragments de code qui suivent créeront la même zone. Dans le premier, on indique la ligne de début puis la ligne de fin en indiquant que l’élément occupe trois lignes. La zone commencera donc sur la première ligne et occupera 3 lignes, jusqu’à la ligne 4.
.box1 { grid-column-start: 1; grid-row-start: 1; grid-row-end: span 3; }
Dans le deuxième exemple, on indique la ligne de fin et le nombre de lignes occupées par l’élément avec span 3. Cela signifie que l’élément partira de la ligne 4 et occupera 3 lignes jusqu’à la ligne 1.
.box1 { grid-column-start: 1; grid-row-start: span 3; grid-row-end: 4; }
Pour vous familiariser avec le positionnement des éléments d’une grille en utilisant les lignes, vous pouvez essayer de construire certaines dispositions fréquemment utilisées en plaçant des éléments sur des grilles avec plus ou moins de pistes. Il faut garder à l’esprit que, lorsqu’on ne place pas explicitement tous les éléments, les éléments restants seront positionnés automatiquement. Cela peut tout à fait être l’objectif recherché mais si ce n’est pas le cas et que vous voyez un élément à un endroit inapproprié, vérifiez que vous lui avez affecté une position au sein de la grille.
Il faut aussi se rappeler que lorsqu’on place les éléments explicitement sur la grille, ceux-ci peuvent se chevaucher. Cela permet d’obtenir certains effets mais attention aux erreurs lorsque c’est la mauvaise ligne de début ou de fin qui est indiquée. Pour régler ce problème, on peut utiliser l’outil de mise en évidence de la grille CSS dans Firefox pour analyser une grille compliquée.
—
Définir des zones sur une grille
Donner un nom à une zone de grille
Un en-tête (header)
Un pied de page (footer)
Une barre latérale (sidebar)
Le contenu principale (content)
Avec grid-area, on affecte un nom à chacune de ces zones. Pour le moment, aucune disposition n’a été créée mais on a des noms qu’on pourra utiliser dans notre disposition :
.header { grid-area: hd; } .footer { grid-area: ft; } .content { grid-area: main; } .sidebar { grid-area: sd; }
.wrapper { display: grid; grid-template-columns: repeat(9, 1fr); grid-auto-rows: minmax(100px, auto); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd mn mn mn mn mn mn" "ft ft ft ft ft ft ft ft ft"; }
<div class="wrapper"> <div class="header">En-tête</div> <div class="sidebar">Barre latérale</div> <div class="content">Contenu</div> <div class="footer">Pied de page</div> </div>
Grâce à cette méthode, il n’est pas nécessaire de gérer chacun des éléments individuellement. Tout est organisé au travers du conteneur. La disposition est décrite grâce à la propriété grid-template-areas.
Laisser une cellule vide
Dans l’exemple précédent, toute la grille est occupée… On peut également utiliser cette méthode pour laisser des cellules vides. Pour cela, il faut utiliser un point à la place d’un nom de zone. Aussi, si on veut que le pied de page soit uniquement affiché sous le contenu, il faudra avoir trois cellules vides sous la barre latérale.
.header { grid-area: hd; } .footer { grid-area: ft; } .content { grid-area: main; } .sidebar { grid-area: sd; }
.wrapper { display: grid; grid-template-columns: repeat(9, 1fr); grid-auto-rows: minmax(100px, auto); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd main main main main main main" ". . . ft ft ft ft ft ft"; }
<div class="wrapper"> <div class="header">En-tête</div> <div class="sidebar">Barre latérale</div> <div class="content">Contenu</div> <div class="footer">Pied de page</div> </div>
Si on veut que la disposition soit bien représentée, on peut utiliser plusieurs points. Tant que ceux-ci ne sont pas séparés par un espace, ils compteront pour une seule cellule. Dans le cas d’une disposition complexe, cela permet d’avoir des lignes et colonnes clairement alignées, y compris dans la règle CSS.
Occuper plusieurs cellules
Dans notre exemple, chacune des zones occupe plusieurs cellules car on a répété le nom de la zone avec des espaces entre (on peut ajouter plus d’espaces si besoin, afin d’avoir une disposition lisible, c’est ce qu’on a fait précédemment pour que hd et ft soient alignés avec main).
La zone qu’on crée avec les noms doit être rectangulaires. Actuellement, il n’existe pas de méthode pour créer une zone avec une forme de L (bien que la spécification indique qu’une prochaine version pourrait couvrir cette fonctionnalité). On peut toutefois agrandir des lignes horizontales aussi simplement que des colonnes. Par exemple, on pourrait avoir la barre latérale qui descend jusqu’en bas en remplaçant les points par sd.
.header { grid-area: hd; } .footer { grid-area: ft; } .content { grid-area: main; } .sidebar { grid-area: sd; }
.wrapper { display: grid; grid-template-columns: repeat(9, 1fr); grid-auto-rows: minmax(100px, auto); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd main main main main main main" "sd sd sd ft ft ft ft ft ft"; }
La valeur utilisée pour grid-template-areas doit obligatoirement décrire une grille complète, sinon elle est considérée invalide et la propriété est ignorée. Cela signifie qu’il faut le même nombre de cellules pour chaque ligne (si une cellule est vide, on l’indiquera avec un point). Si des zones ne sont pas rectangulaires, cela sera également considéré comme invalide.
Redéfinir une grille avec des media queries
Notre disposition fait désormais partie de notre feuille de style CSS. On peut donc l’adapter très facilement pour différentes résolutions. On peut redéfinir la position des objets sur la grille ou la grille elle-même, ou les deux simultanément.
Pour ce faire, on définit les noms des zones en dehors de toute media query afin de pouvoir y accéder quel que soit l’endroit où la zone sera placée.
Pour la disposition vue précédemment, on définit ici une disposition par défaut sur une seule colonne pour les affichages étroits. On a donc une seule piste sur laquelle s’empilent les objets :
.header { grid-area: hd; } .footer { grid-area: ft; } .content { grid-area: main; } .sidebar { grid-area: sd; } .wrapper { display: grid; grid-auto-rows: minmax(100px, auto); grid-template-columns: 1fr; grid-template-areas: "hd" "main" "sd" "ft"; }
On peut ensuite redéfinir la disposition à l’intérieur des différentes media queries utilisées pour avoir une disposition sur deux colonnes, voire trois lorsque l’espace le permet. On notera que pour la disposition la plus large, on a une grille organisée sur 9 colonnes/pistes et on redéfinit l’emplacement des objets avec grid-template-areas.
@media (min-width: 500px) { .wrapper { grid-template-columns: repeat(9, 1fr); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd main main main main main main" "sd sd sd ft ft ft ft ft ft"; } } @media (min-width: 700px) { .wrapper { grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd main main main main main ft ft"; } }
Utiliser grid-template-areas pour des éléments d’interface utilisateur
La plupart des exemples illustrent une utilisation de la grille pour la disposition principale de la page. Toutefois, une grille peut également être utile pour les petits éléments. grid-template-areas est assez pratique car elle permet de voir facilement à quoi ressemblera l’élément.
Exemple d’objet média
Dans l’exemple qui suit, on crée un objet « media » qui servira de composant pour afficher un media (une image par exemple) d’un côté et un texte de l’autre. On pourra ainsi voir l’effet obtenu en changeant la disposition avec l’image à droite ou à gauche.
Ici, la grille se compose de deux pistes en colonnes. La colonne pour l’image est dimensionnée avec 1fr et celle pour le texte reçoit 3fr. Si on souhaitait utiliser une largeur fixe pour l’image, on aurait pu utiliser des pixels pour définir la taille de la colonne et utiliser 1fr pour la zone du texte. Cette colonne de 1fr aurait alors occupé le reste de l’espace.
Pour la zone dédiée à l’image, on crée une zone de grille intitulée img et pour le texte, on crée une seconde zone intitulée content. Ensuite, on utilise ces noms pour créer l’organisation via la propriété grid-template-areas.
* {box-sizing: border-box;} .media { border: 2px solid #f76707; border-radius: 5px; background-color: #fff4e6; max-width: 400px; } .media { display: grid; grid-template-columns: 1fr 3fr; grid-template-areas: "img content"; margin-bottom: 1em; } .media .image { grid-area: img; background-color: #ffd8a8; } .media .text { grid-area: content; padding: 10px; }
<div class="media"> <div class="image"></div> <div class="text"> Dans cet exemple, on peut utiliser grid-template-areas pour échanger les places du texte et du media. </div> </div>
Afficher l’image de l’autre côté
Si on a besoin d’afficher l’image d l’autre côté, il suffit de redéfinir une grille pour laquelle la piste qui mesure 1fr est en dernier et d’échanger les valeurs dans grid-template-areas.
* {box-sizing: border-box;} .media { border: 2px solid #f76707; border-radius: 5px; background-color: #fff4e6; max-width: 400px; } .media { display: grid; grid-template-columns: 1fr 3fr; grid-template-areas: "img content"; margin-bottom: 1em; } .media.flipped { grid-template-columns: 3fr 1fr; grid-template-areas: "content img"; } .media .image { grid-area: img; background-color: #ffd8a8; } .media .text { grid-area: content; padding: 10px; }
<div class="media flipped"> <div class="image"></div> <div class="text"> Dans cet exemple, on peut utiliser grid-template-areas pour échanger les places du texte et du media. </div> </div>
Les propriétés raccourcies pour les grilles CSS
Nous avons vu différentes façons de placer des objets sur une grille et plusieurs des propriétés utilisées pour définir une grille. Voyons maintenant les propriétés raccourcies qui sont disponibles pour les grilles CSS et qui permettent de rendre le code un peu plus concis.
Attention, ces propriétés peuvent parfois devenir complexes à lire, que ce soit pour les autres développeurs qui liraient votre code voire pour vous-même d’ici quelques semaines. Cependant, elles font partie de la spécification et vous pourrez les rencontrer dans des exemples ou dans d’autres bases de code.
Avant d’utiliser une propriété raccourcie, il est préférable de se rappeler qu’une propriété raccourcie permet d’en définir plusieurs grâce à une seule règle mais aussi qu’une propriété raccourcie réinitialise les propriétés avec leurs valeurs initiales lorsqu’elles ne sont pas déclarées via la propriété raccourcie. Aussi, si vous utilisez une propriété raccourcie, sachez qu’elle peut réinitialiser une propriété que vous auriez utilisé autre part.
Les deux propriétés raccourcies pour les grilles sont grid-template et grid.
grid-template
La propriété grid-template permet de définir les propriétés suivantes :
Cette propriété est appelée propriété raccourcie « explicite » car elle permet de paramétrer les aspects d’une grille définie explicitement. Elle n’a pas d’impact sur les propriétés qui créeraient des lignes ou colonnes implicites.
Le fragment de code suivant crée une disposition identique à celle que nous avons vu plus haut dans cet article.
.wrapper { display: grid; grid-template: "hd hd hd hd hd hd hd hd hd" minmax(100px, auto) "sd sd sd main main main main main main" minmax(100px, auto) "ft ft ft ft ft ft ft ft ft" minmax(100px, auto) / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr ; }
La première valeur correspond à celle de grid-template-areas mais on déclare également les tailles de chaque ligne à la fin de chaque ligne (avec minmax(100px, auto)).
Après la valeur de grid-template-areas, on a un barre oblique (/) puis une liste de pistes qui définit les colonnes explicitement.
grid
La propriété grid va un cran plus loin et définit également les propriétés utilisées par la grille implicite. Elle permet de paramétrer :
Cette propriété réinitialise également la propriété gap avec la valeur 0 mais, en revanche, elle ne permet pas de définir des espaces.
On peut utiliser la même syntaxe qu’avec grid-template mais attention, cela réinitialisera les valeurs des autres propriétés :
.wrapper { display: grid; grid: "hd hd hd hd hd hd hd hd hd" minmax(100px, auto) "sd sd sd main main main main main main" minmax(100px, auto) "ft ft ft ft ft ft ft ft ft" minmax(100px, auto) / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr ; }
Dans les articles suivants, nous verrons les fonctionnalités offertes par cette propriété raccourcie, notamment pour le placement automatique et pour la propriété grid-auto-flow.
Après ces quelques guides, vous devriez désormais être en mesure de créer des grilles et de placer les éléments sur des lignes ou grâce à des zones nommées. Prenez le temps de construire certains motifs « classiques » à l’aide de grille pour mieux apprendre en manipulant. Au fur et à mesure, vous aurez des questions et arriverez sur des scénarios que nous n’avons pas encore évoqués. Dans la suite de ces articles, nous nous intéresserons plus en détails aux autres éléments de la spécification afin de pouvoir créer des dispositions plus complexes.
—
Utiliser des lignes nommées sur une grille
Dans les articles précédents, on a vu comment placer des objets sur les lignes définies par les pistes de la grilles. On a également vu comment placer des objets sur des zones nommées. Dans ce guide, nous allons combiner ces deux concepts et apprendre à placer les objets sur des lignes avec des noms. Le nommage des lignes peut s’avérer très utile mais un aspect encore plus intéressant consiste à combiner les noms et les tailles de pistes. Cela sera plus clair lorsque nous aurons vu les différents exemples.
Nommer des lignes lorsqu’on définit une grille
Lorsqu’on définit une grille avec grid-template-rows et grid-template-columns, on peut donner des noms aux lignes (toutes ou seulement quelques unes). Pour illustrer ce point, nous allons reprendre la disposition utilisée dans l’article sur le placement sur les lignes. Cette fois, nous allons utiliser des lignes avec des noms.
Lorsqu’on définit la grille, on nomme les lignes entre crochets. Ces noms peuvent être n’importe quelle valeur. Ici, on définit un nom pour le début et la fin du conteneur, pour les lignes et pour les colonnes. On définit les blocs du centres (ici content-start et content-end), à la fois pour les lignes et pour les colonnes. Il n’est pas nécessaire de nommer toutes les lignes de la grille, on peut très bien uniquement nommer celles qui sont importantes.
.wrapper { display: grid; grid-template-columns: [main-start] 1fr [content-start] 1fr [content-end] 1fr [main-end]; grid-template-rows: [main-start] 100px [content-start] 100px [content-end] 100px [main-end]; }
Une fois que les lignes sont nommées, on peut utiliser ce nom plutôt que le numéro de ligne afin de placer les éléments.
.box1 { grid-column-start: main-start; grid-row-start: main-start; grid-row-end: main-end; } .box2 { grid-column-start: content-end; grid-row-start: main-start; grid-row-end: content-end; } .box3 { grid-column-start: content-start; grid-row-start: main-start; } .box4 { grid-column-start: content-start; grid-column-end: main-end; grid-row-start: content-end; }
<div class="wrapper"> <div class="box1">Un</div> <div class="box2">Deux</div> <div class="box3">Trois</div> <div class="box4">Quatre</div> </div>
Tout le reste continue de fonctionner de la même façon. Vous pouvez aussi utiliser des noms et des numéros. Le nommage des lignes est utile lorsqu’on souhaite créer une disposition responsive où on redéfinit la grille plutôt que d’avoir à redéfinir la position du contenu en changeant les numéros de lignes dans les media queries.
Donner plusieurs noms à une ligne
On peut donner plusieurs noms à une ligne (par exemple une ligne qui décrirait la fin de la barre latérale et le début du contenu principal). Pour cela, à l’intérieur des crochets, on déclare les différents noms, séparés par un espace : [sidebar-end main-start]. On peut ensuite désigner la ligne par l’un de ces noms.
Définir des zones de grilles implicites à l’aide de lignes nommées
Plus haut, nous avons vu qu’il était possible de donner n’importe quel nom à une ligne. D’un point de vue technique, ce nom est un identifiant personnalisé (ou custom ident), c’est-à-dire un nom défini par l’auteur de la feuille de style. Pour être plus précis, ce nom ne doit pas reprendre les mots-clés qui apparaissent dans la spécification et ne doit pas être source de confusion (on évitera ainsi d’utiliser span). Les identifiants ne sont pas mis entre quotes.
Bien qu’on puisse choisir n’importe quel nom (avec les contraintes qu’on vient d’énoncer), si on utilise les suffixes -start et -end pour désigner les lignes qui entourent une zone (comme dans l’exemple ci-avant), la grille créera automatiquement une zone nommée avec le nom utilisé devant ces suffixes. Si on reprend l’exemple précédent où on utilise content-start et content-end pour les lignes et pour les colonnes, cela signifie qu’on a, implicitement, une zone de grille intitulée content qu’on peut également manipuler
On utilise les mêmes définitions qu’avant mais cette fois, nous allons placer un objet dans la zone intitulée content.
.wrapper { display: grid; grid-template-columns: [main-start] 1fr [content-start] 1fr [content-end] 1fr [main-end]; grid-template-rows: [main-start] 100px [content-start] 100px [content-end] 100px [main-end]; } .thing { grid-area: content; }
<div class="wrapper"> <div class="thing"> Je suis dans une zone nommée content. </div> </div>
Il n’est pas nécessaire de définir l’emplacement de cette zone avec grid-template-areas car les lignes suffisent à créer la zone et à la placer.
Définir des lignes implicites à l’aide de zones nommées
Nous avons vu comment des lignes nommées permettaient de créer des zones nommées. Cela fonctionne également dans l’autre sens. Les zones nommées créent aussi des lignes nommées qui peuvent ensuite être utilisées pour placer les objets. Si on reprend l’exemple utilisé dans le guide sur les zones nommées, on peut utiliser les lignes créées implicitement pour voir comment cela fonctionne.
Dans cet exemple, on ajoute un élément div supplémentaire et on lui ajoute la classe overlay. On déclare des zones nommées à l’aide de grid-area puis on indique la disposition via la propriété grid-template-areas. Les noms utilisés pour les zones sont :
hd
ft
main
sd
Cela crée implicitement les lignes et colonnes suivantes :
hd-start
hd-end
sd-start
sd-end
main-start
main-end
ft-start
ft-end
Dans l’image qui suit, on peut voir l’emplacement de ces lignes. Certaines lignes peuvent avoir deux noms (par exemple, sd-end et main-start font référence à la même ligne verticale).
On peut positionner overlay grâce à ces lignes implicites, de la même façon qu’on aurait positionner un objet avec des lignes créées explicitement :
.wrapper { display: grid; grid-template-columns: repeat(9, 1fr); grid-auto-rows: minmax(100px, auto); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd main main main main main main" "ft ft ft ft ft ft ft ft ft"; } .header { grid-area: hd; } .footer { grid-area: ft; } .content { grid-area: main; } .sidebar { grid-area: sd; } .wrapper > div.overlay { z-index: 10; grid-column: main-start / main-end; grid-row: hd-start / ft-end; border: 4px solid rgb(92,148,13); background-color: rgba(92,148,13,.4); color: rgb(92,148,13); font-size: 150%; }
<div class="wrapper"> <div class="header">En-tête</div> <div class="sidebar">Barre latérale</div> <div class="content">Contenu</div> <div class="footer">Pied de page</div> <div class="overlay">Masque</div> </div>
Grâce à tout ça, on voit qu’on peut créer des lignes à partir de zones nommées et créer des zones à partir de lignes nommées. Aussi, mieux vaut prendre le temps de réfléchir aux noms utilisés lorsqu’on définit un grille. En effet, plus les noms utilisés seront clairs, plus la maintenance et le travail d’équipe seront simplifiés.
Utiliser plusieurs lignes avec le même nom : repeat()
Si vous souhaitez que chaque ligne ait un nom différent, il faudra alors définir la piste de façon détaillée et non utiliser la syntaxe avec repeat() car il faut préciser le nom de la ligne entre crochets lorsqu’on définit les pistes. Si vous utilisez la syntaxe avec repeat(), vous obtiendrez plusieurs lignes avec le même nom… ce qui peut également être utile.
Une grille à 12 colonnes avec repeat()
Dans l’exemple qui suit, nous allons créer une grille avec douze colonnes de même largeur. Avant de définir la taille d’une piste pour la colonne (1fr), on définit un nom : [col-start]. Cela signifie qu’on aura une grille avec 12 colonnes, toutes intitulées col-start et qui mesureront chacune 1fr de large.
.wrapper { display: grid; grid-template-columns: repeat(12, [col-start] 1fr); }
Une fois la grille créée, on peut y placer les objets. On a alors plusieurs lignes avec le nom col-start et si on place un objet après la ligne col-start, la grille utilisera la première ligne intitulée col-start (dans notre cas, c’est la ligne la plus à gauche). Pour indiquer une autre ligne, on utilisera le nom, suivi du numéro de cette ligne. Ainsi, pour placer un objet à partir de la première ligne jusqu’à la cinquième, on pourra utiliser :
.item1 { grid-column: col-start / col-start 5 }
On peut également utiliser le mot-clé span. Avec la règle suivante, le deuxième objet sera placé à partir de la septième ligne et occupera 3 lignes :
.item2 { grid-column: col-start 7 / span 3; }
<div class="wrapper"> <div class="item1">Je vais de col-start 1 à col-start 5</div> <div class="item2">Je vais de col-start 7 et je m'étends sur 3 lignes</div> </div>
Si vous observez cette disposition grâce à l’outil de mise en évidence des grilles dans Firefox, vous verrez les différentes lignes et le placement des éléments sur ces lignes :
Définir des lignes nommées avec une liste de piste
La syntaxe repeat() permet également d’utiliser une liste de plusieurs pistes et pas uniquement une seule piste. Dans la règle qui suit, on crée une grille composée de huit pistes qui commence par une colonne plus étroite (1fr), intitulée col1-start, et qui est suivie par une colonne plus large (3fr), intitulée col2-start.
.wrapper { grid-template-columns: repeat(4, [col1-start] 1fr [col2-start] 3fr); }
Si on utilise repeat() et qu’on place deux lignes l’une à la suite de l’autre, ces lignes seront fusionnées et on aura le même résultat que si on avait donné plusieurs noms à un même ligne. La règle suivante permet de créer quatre pistes dont la largeur est 1fr, chacune avec un début et une fin.
.wrapper { grid-template-columns: repeat(4, [col-start] 1fr [col-end] ); }
Si on écrivait la même définition sans utiliser repeat(), on aurait la forme suivante :
.wrapper { grid-template-columns: [col-start] 1fr [col-end col-start] 1fr [col-end col-start] 1fr [col-end col-start] 1fr [col-end]; }
Si vous utilisez une liste de pistes, vous pouvez utiliser le mot-clé span pour indiquer le nombre de lignes à occuper mais aussi pour indiquer le nombre de lignes à occuper qui ont un nom donné.
.wrapper { display: grid; grid-template-columns: repeat(6, [col1-start] 1fr [col2-start] 3fr); } .item1 { grid-column: col1-start / col2-start 2 } .item2 { grid-row: 2; grid-column: col1-start 2 / span 2 col1-start; }
<div class="wrapper"> <div class="item1">Je suis placé à partir de la première col1-start et jusqu'à la deuxième col2-start.</div> <div class="item2">Je suis placé à partir de la deuxième col1-start et je m'étend sur deux lignes nommées col1-start</div> </div>
Cadre d’une grille à 12 colonnes
Avec ces trois derniers articles, nous avons vu de nombreuses façons qui permettaient de placer des objets sur une grille. Cela peut sembler un peu trop inutilement compliqué mais il faut garder à l’esprit que toutes ne sont pas obligatoirement nécessaires. Dans la pratique, utiliser des zones nommés pour des dispositions simples permet d’avoir une représentation visuelle simple et de déplacer les différents objets facilement sur la grille.
Si on travaille avec une disposition sur plusieurs colonnes (comme celles utilisées dans ces derniers exemples), les lignes nommées feront parfaitement l’affaire. Si vous prenez par exemple des frameworks tels que Foundation ou Bootstrap, ceux-ci fonctionnent sur une grille avec 12 colonnes. Le framework importe ensuite le code nécessaire aux différents calculs afin de s’assurer que l’ensemble des colonnes fasse 100%. En utilisant une grille CSS, le seule code nécessaire pour obtenir un tel framework se résume à :
.wrapper { display: grid; grid-gap: 10px; grid-template-columns: repeat(12, [col-start] 1fr); }
On peut alors utiliser ce modèle pour mettre en forme notre page. Par exemple, on peut créer une disposition avec trois colonnes, un en-tête et un pied de page avec les règles suivantes :
<div class="wrapper"> <header class="main-header">Je suis l'en-tête</header> <aside class="side1">Je suis la barre latérale 1</aside> <article class="content">Je suis l'article</article> <aside class="side2">Je suis la barre latérale 2</aside> <footer class="main-footer">Je suis le pied de page</footer> </div>
Pour placer ces éléments, on utilise la grille de la façon suivante :
.main-header, .main-footer { grid-column: col-start / span 12; } .side1 { grid-column: col-start / span 3; grid-row: 2; } .content { grid-column: col-start 4 / span 6; grid-row: 2; } .side2 { grid-column: col-start 10 / span 3; grid-row: 2; }
Là encore, l’outil de mise en évidence de la grille permet de voir comment le placement fonctionne :
Et voilà tout ce dont on a besoin. Aucun calcul compliqué, la grille a automatiquement retiré la gouttière de 10 pixels avant d’affecter l’espace aux pistes qui mesurent 1fr. Lorsque vous construirez vos propres disposition, vous serez plus à l’aise avec la syntaxe et utiliserez les techniques qui sont les plus pertinentes pour vos projets. Essayez de construire cetaines dispositions classiques avec des différentes méthodes, vous deviendrez plus efficaces pour manipuler les grilles CSS. Dans le prochain guide, nous verrons comment la grille peut placer des objets automatiquement, sans même avoir besoin d’utiliser les propriétés de placement !
—
Le placement automatique sur une grille CSS
En plus de pouvoir placer des objets de façon précise sur une grille, la spécification pour les grilles CSS définit le comportement obtenu lorsque certains des objets ne sont pas placés sur la grille (voire aucun). Pour voir comment fonctionne le placement automatique, il suffit de créer une grille avec un ensemble d’objets. Sans fournir aucune information de placement, ces objets se placeront chacun sur une cellule de la grille.
Placement automatique
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px; }
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
Définir des règles pour le placement automatique
Comme on peut le voir dans l’exemple précédent, si on crée une grille sans définir de placement, tous les objets occuperont chacun une cellule de la grille. Par défaut, les objets sont placés au fur et à mesure sur les lignes horizontales de la grille. Si on a créé des lignes supplémentaires avec grid-template-rows, les objets suivants seront placés sur ces lignes. En revanche, si la grille ne possède pas suffisamment de lignes sur la grille explicite, de nouvelles lignes, implicites, seront créées.
Dimensionner les lignes de la grille implicite
Par défaut, les lignes implicites créées automatiquement ont une taille automatique. Autrement dit, elles seront dimensionnées pour contenir les éléments qu’elles doivent placer sans que ceux-ci dépassent.
Il est toutefois possible de contrôler la taille de ces lignes grâce à la propriété grid-auto-rows. Ainsi, si on veut que les lignes créées automatiquement mesurent 100 pixels de haut, on utilisera :
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px; grid-auto-rows: 100px; }
Dimensionner les lignes avec minmax()
On peut utiliser la fonction minmax() pour la valeur de grid-auto-rows afin de créer des lignes avec une taille minimale mais qui puissent être plus grandes si le contenu est plus grand que cette taille minimale.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre <br>Cette cellule <br>a du contenu <br>supplémentaire <br>et max vaut auto <br>afin que la ligne <br>se développe. </div> <div>Five</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px; grid-auto-rows: minmax(100px, auto); }
Dimensionner les lignes avec une liste de pistes
On peut aussi passer en argument une liste de pistes qui se répèteront. Dans l’exemple ci-après, on crée une piste implicite pour une ligne de 100 pixels et une seconde de 200px. Ce motif sera utilisé tant que du contenu sera ajouté à la grille implicite.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> <div>Six</div> <div>Sept</div> <div>Huit</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 10px; grid-auto-rows: 100px 200px; }
Utiliser le placement automatique pour les colonnes
On peut également paramétrer la grille pour que les objets soient placés automatiquement en suivant les colonnes de la grille. Pour obtenir ce résultat, on utilisera la propriété grid-auto-flow avec la valeur column. Dans ce cas, la grille ajoutera les objets dans les lignes verticales définies avec grid-template-rows. Lorsqu’une colonne sera pleine, les prochains objets seront placés dans la colonne explicite suivante ou dans une colonne implicite créée automatiquement s’il n’y a plus assez de colonnes explicites. La taille des pistes pour les colonnes implicites peut être définie avec grid-auto-columns, cette dernière fonctionne de façon analogue à grid-auto-rows.
Dans le prochain exemple, on crée une grille avec trois lignes qui mesurent chacune 200 pixels de haut. On utilise le placement automatique en colonne. La première colonne qui sera créée mesurera 300 pixels de large, ensuite on aura une colonne de 100 pixels de large et ainsi de suite jusqu’à ce que tous les éléments puissent être placés.
.wrapper { display: grid; grid-template-rows: repeat(3, 200px); grid-gap: 10px; grid-auto-flow: column; grid-auto-columns: 300px 100px; }
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> <div>Six</div> <div>Sept</div> <div>Huit</div> </div>
L’ordre des éléments placés automatiquement
Une grille peut contenir un mélange d’éléments. Certains éléments peuvent avoir une position définie et d’autres être placés automatiquement. Ce placement automatique peut s’avérer utile lorsque l’ordre des éléments dans le document est celui qu’on veut utiliser pour organiser la grille : il n’y a alors pas besoin d’écrire de règles CSS pour positionner les éléments un par un. La spécification détaille exhaustivement l’algorithme de placement des objets sur la grille, mais voyons ici les quelques règles simples qu’il faut principalement retenir.
Modification de l’ordre du document
Le placement des éléments qui n’ont pas eu d’ordre défini sont placés selon l’algorithme décrit dans la section “order modified document order”. Cela signifie que si on utilise uniquement la propriété order, les éléments seront placés selon cet ordre plutôt que selon l’ordre indiqué par le DOM. Sinon, l’ordre des éléments sera celui décrit par le document source.
Les éléments avec des propriétés de placement
La grille commencera par placer les éléments pour lesquels on a défini une position. Dans l’exemple qui suit, on a une grille avec 12 éléments, l’élément 2 et l’élément 5 sont placés en utilisant les lignes. On put voir comment ces deux éléments sont placés et comment les autres sont placés automatiquement dans les espaces restants. Les objets placés automatiquement seront placés avant les éléments qui sont placés, dans l’ordre du DOM.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> <div>Six</div> <div>Sept</div> <div>Huit</div> <div>Neuf</div> <div>Dix</div> <div>Onze</div> <div>Douze</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; grid-gap: 10px; } .wrapper div:nth-child(2) { grid-column: 3; grid-row: 2 / 4; } .wrapper div:nth-child(5) { grid-column: 1 / 3; grid-row: 1 / 3; }
Gérer les éléments qui s’étalent sur plusieurs pistes
On peut utiliser les propriétés de placement tout en tirant parti du placement automatique. Dans le prochain exemple, on complète la disposition en indiquant que les éléments 1, 4 et 9 (4n+1) doivent occuper deux pistes, pour les colonnes et pour les lignes. Pour obtenir ce résultat, on utilise les propriétés grid-column-end et grid-row-end avec la valeur span 2. La ligne de début sera déterminée automatiquement et la ligne de fin sera deux pistes plus loin.
On peut voir coment cela laisse des espaces dans la grille car lorsqu’un élément placé automatiquement n’a pas suffisamment de place sur une piste, une nouvelle ligne sera créée jusqu’à ce que l’élément ait la place.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> <div>Six</div> <div>Sept</div> <div>Huit</div> <div>Neuf</div> <div>Dix</div> <div>Onze</div> <div>Douze</div> </div>
.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; grid-gap: 10px; } .wrapper div:nth-child(4n+1) { grid-column-end: span 2; grid-row-end: span 2; background-color: #ffa94d; } .wrapper div:nth-child(2) { grid-column: 3; grid-row: 2 / 4; } .wrapper div:nth-child(5) { grid-column: 1 / 3; grid-row: 1 / 3; }
Combler les espaces
En dehors des éléments placés explicitement, la grille place les éléments automatiques en respectant l’ordre du DOM. C’est généralement le résultat qu’on souhaite lorsqu’on met en forme un document comme un formulaire. Toutefois on veut parfois obtenir une disposition plus dense, sans vide entre les différents éléments.
Pour cela, sur le conteneur, on ajoute la propriété grid-auto-flow avec la valeur dense. C’est la même propriété qu’on utilise pour modifier l’ordre du flux avec column. On peut aussi obtenir une disposition dense, rangée par colonne en utilisant les deux valeurs pour la propriété : grid-auto-flow: column dense.
Avec cette valeur, la grille cherchera donc à combler les espaces qu’elle a laissés quitte à ne pas respecter l’ordre du DOM. En revanche, l’ordre de la navigation au clavier (tab order) suivra toujours l’ordre du document. Nous étudierons cet aspect plus en détails dans un article sur l’accessibilité.
<div class="wrapper"> <div>Un</div> <div>Deux</div> <div>Trois</div> <div>Quatre</div> <div>Cinq</div> <div>Six</div> <div>Sept</div> <div>Huit</div> <div>Neuf</div> <div>Dix</div> <div>Onze</div> <div>Douze</div> </div>
.wrapper div:nth-child(4n+1) { grid-column-end: span 2; grid-row-end: span 2; background-color: #ffa94d; } .wrapper div:nth-child(2) { grid-column: 3; grid-row: 2 / 4; } .wrapper div:nth-child(5) { grid-column: 1 / 3; grid-row: 1 / 3; } .wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; grid-gap: 10px; grid-auto-flow: dense; }
Les éléments anonymes de la grille
Dans la spécification, on utilise le concept d’élément anonyme. Ces éléments sont ceux qui sont créés lorsqu’on a une chaîne de caractères dans le conteneur de la grille et que celle-ci n’est pas contenue dans un autre élément. Dans l’exemple ci-après, on a trois éléments sur la grille : le premier est un élément anonyme car il n’est placé dans aucun élément, il sera alors placé automatiquement. Les deux éléments suivants sont placés dans des div et peuvent être placés automatiquement ou grâce à une autre méthode de positionnement.
<div class="grid"> Je suis une chaîne de caractères et je serai placé automatiquement. <div>Un élément de la grille</div> <div>Un élément de la grille</div> </div>
Les éléments anonymes sont toujours placés automatiquement car on ne peut pas les cibler autrement. Aussi, si on a du texte sans balise dans la grille, il faut se rappeler que celui-ci peut être placé à un endroit imprévu du fait des règles de placement automatique.
Les cas d’utilisation pour le placement automatique
Le placement automatique peut être utile lorsqu’on a un ensemble d’objets qui se ressemblent. Ce peut être des éléments qui n’ont pas d’ordre logique particulier : une galerie de photos, une liste de produits. Dans ces cas de figure, on peut choisir d’utiliser une disposition dense afin de combler les trous de la grille. Dans l’exemple qui représente la galerie d’images, on a certaines images en paysage et d’autres en portrait (lorsqu’on utilise la classe landscape l’élément s’étend sur deux colonnes). On utilise ensuite grid-auto-flow: dense afin de créer une grille dense.
.wrapper { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); grid-gap: 10px; grid-auto-flow: dense; list-style: none; margin: 1em auto; padding: 0; max-width: 800px; } .wrapper li { border: 1px solid #ccc; } .wrapper li.landscape { grid-column-end: span 2; } .wrapper li img { display: block; object-fit: cover; width: 100%; height: 100%; }
<ul class="wrapper"> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> <li class="landscape"><img src="http://placehold.it/350x200" alt="placeholder"></li> <li class="landscape"><img src="http://placehold.it/350x200" alt="placeholder"></li> <li class="landscape"><img src="http://placehold.it/350x200" alt="placeholder"></li> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> <li class="landscape"><img src="http://placehold.it/350x200" alt="placeholder"></li> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> <li><img src="http://placehold.it/200x300" alt="placeholder"></li> </ul>
Le placement automatique peut également aider à disposer des éléments d’interface utilisateur qui ont un ordre logique. Dans l’exemple suivant, on voit comment manipuler les listes de définition. Les listes de définition sont intéressantes car il n’y a pas de niveau de regroupement pour regrouper un terme et ses définitions. Dans cet exemple, on autorise le placement automatique mais on a une classe pour qu’un élément dt démarre sur la première ligne et que l’élément dd sur la ligne 2. On s’assure ainsi que les termes sont bien en face de chaque définition, peu importe le nombre de définitions qu’on a pour un terme.
Autre exemple
<div class="wrapper"> <dl> <dt>Mammals</dt> <dd>Cat</dd> <dd>Dog</dd> <dd>Mouse</dd> <dt>Fish</dt> <dd>Guppy</dd> <dt>Birds</dt> <dd>Pied Wagtail</dd> <dd>Owl</dd> <dl> </div>
dl { display: grid; grid-template-columns: auto 1fr; max-width: 300px; margin: 1em; line-height: 1.4; } dt { grid-column: 1; font-weight: bold; } dd { grid-column: 2; }
Note : Voir cet article de SitePoint à propos de la disposition en briques pour d’autres cas d’utilisation.
Qu’est-ce que le placement automatique ne permet pas de réaliser (actuellement) ?
Certaines questions se posent encore. Actuellement on ne peut pas cibler toutes les autres cellules de la grille. On ne peut pas non plus définir une règle pour « placer tous les éléments automatiquement après la prochaine ligne intitulée n » (pour que certaines lignes soient sautées). Cette question est décrite sur le dépôt GitHub du CSSWG, n’hésitez pas à ajouter vos exemples de scénarios.
Si vous rencontrez des cas d’utilisation problématiques avec le placement automatique et les grilles, vous pouvez consulter les issues existantes et les compléter ou ajouter les vôtres. Cela permettra que les prochaines versions de la spécification soient meilleures.
—
L’alignement des boîtes avec les grilles CSS
Si vous connaissez les boîtes flexibles (flexbox) vous savez déjà comment aligner les éléments flexibles à l’intérieur d’un conteneur flexible. Ces propriétés d’alignement, initialement spécifiée dans la spécification des boîtes flexibles, sont désormais spécifiées dans une nouvelle spécification Box Alignment Level 3. Cette spécification détaille le fonctionnement de l’alignement pour les différentes méthodes de disposition.
Chaque méthode de disposition qui implémente cette nouvelle spécification se comportera légèrement différemment selon les différences de contraintes et de fonctionnalités (et aussi selon le comportement historique). On ne pourra donc pas avoir un alignement exactement homogène. La spécification pour l’alignement des boîtes détaille le fonctionnement de chaque méthode mais malheureusement, à l’heure actuelle, aucun navigateur ne prend en charge cette spécification. À l’heure actuelle, les navigateurs respectent les règles de cette spécification pour l’alignement et la répartition de l’espace lorsqu’on utilise une disposition en grille. Dans cet article, nous verrons comment celles-ci fonctionnent. On retrouvera de nombreux points communs avec les boîtes flexibles pour le fonctionnement de ces propriétés et valeurs. Toutefois, les grilles fonctionnant sur deux axes et les boîtes flexibles sur un seul, il faudra faire attention à quelques différences. Commençons par analyser les deux axes utilisés lorsqu’il s’agit d’aligner des objets sur une grille.
Les deux axes d’une grille
Lorsqu’on manipule une grille, on dispose de deux axes sur lesquels aligner les objets. L’axe de bloc et l’axe en ligne. L’axe de bloc est l’axe selon lequel les blocs sont disposés quand on a une disposition en bloc (block layout). Par exemple, si on a deux paragraphes sur une page, par défaut, ils s’affichent l’un en dessous de l’autre.
L’axe en ligne est orthogonal à l’axe de bloc. C’est la direction selon laquelle progresse le texte.
Grâce aux propriétés et à leurs valeurs, nous serons en mesure d’aligner le contenu de la grillle par rapport à ces deux axes.
Aligner des objets sur l’axe de bloc (block axis)
Les propriétés align-self et align-items permettent de contrôler l’alignement selon l’axe de bloc. Lorsqu’on utilise ces propriétés, on modifie l’alignement de l’objet au sein de la zone de grille sur laquelle il est placé.
Utiliser align-items
Dans l’exemple suivant, on a quatre zones sur la grille. On peut utiliser la propriété align-items sur le conteneur de la grille afin d’aligner les objets avec l’une des valeurs suivantes :
auto
normal
start
end
center
stretch
baseline
first baseline
last baseline
.wrapper { display: grid; grid-template-columns: repeat(8, 1fr); grid-gap: 10px; grid-auto-rows: 100px; grid-template-areas: "a a a a b b b b" "a a a a b b b b" "c c c c d d d d" "c c c c d d d d"; align-items: start; } .item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Lorsqu’on utilise align-self: start, la hauteur de chaque <div> sera déterminée par le contenu du <div>. En revanche, si on n’utilise pas align-self, chaque <div> sera étiré afin de remplir la zone de la grille.
La propriété align-items définit en fait la valeur de la propriété align-self pour tous les éléments fils de la grille. Cela signifie qu’on peut avoir un réglage plus fin sur chacun des objets de la grille en utilisant align-self pour les objets.
Utiliser align-self
Dans le prochain exemple, on utilise la propriété align-self afin d’illustrer les différentes valeurs pour l’alignement. La première zone illustre le comportement par défaut pour align-self : l’objet est étiré. Le deuxième objet utilise la valeur start, le troisième utilise end et le quatrième utilise center.
.wrapper { display: grid; grid-template-columns: repeat(8, 1fr); grid-gap: 10px; grid-auto-rows: 100px; grid-template-areas: "a a a a b b b b" "a a a a b b b b" "c c c c d d d d" "c c c c d d d d"; } .item1 { grid-area: a; } .item2 { grid-area: b; align-self: start; } .item3 { grid-area: c; align-self: end; } .item4 { grid-area: d; align-self: center; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Gestion des objets avec un ratio intrinsèque
La spécification indique que le comportement par défaut pour align-self est d’étirer l’objet sauf si celui-ci possède un ratio intrinsèque. Dans ce cas, le comportement par défaut correspond à la valeur start. En effet, si le comportement par défaut était le même pour les éléments avec un ratio intrinsèque (une image matricielle par exemple), l’étirement distordrait l’objet.
Bien que ce comportement ait récemment été clarifié dans la spécification, il n’est pas encore implémenté dans les différents navigateurs. Pour le moment, il faut donc s’assurer d’utiliser align-self et justify-self avec les valeurs start pour les éléments concernés comme les images. Cela correspondra au comportement par défaut lorsqu’il aura été implémenté.
Justifier les objets sur l’axe en ligne (inline axis)
align-items et align-self gèrent l’alignement des objets sur l’axe de bloc. justify-items et justify-self permettent quant à eux de gérer l’alignement sur l’axe en ligne. Les valeurs disponibles sont les mêmes que pour align-self :
auto
normal
start
end
center
stretch
baseline
first baseline
last baseline
Juste après, on voit le même exemple qu’avec align-items où on a utilisé la propriété justify-self.
Là encore, la valeur par défaut stretch pour les objets qui n’ont pas de ratio intrinsèque. Cela signifie que, par défaut, les objets de la grille couvriront l’ensemble de la zone de grille sur laquelle ils sont placés. Dans l’exemple qui suit, le premier objet illustre cet alignement par défaut.
.wrapper { display: grid; grid-template-columns: repeat(8, 1fr); grid-gap: 10px; grid-auto-rows: 100px; grid-template-areas: "a a a a b b b b" "a a a a b b b b" "c c c c d d d d" "c c c c d d d d"; } .item1 { grid-area: a; } .item2 { grid-area: b; justify-self: start; } .item3 { grid-area: c; justify-self: end; } .item4 { grid-area: d; justify-self: center; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Comme pour align-self et align-items, on peut utiliser la propriété justify-items sur le conteneur de la grille afin de régler la valeur de justify-self pour l’ensemble des objets de la grille.
Les propriétés justify-self et justify-items ne sont pas disponibles lorsqu’on utilise les boîtes flexibles car celles-ci s’étendent uniquement sur une dimension. Pour aligner les éléments sur l’axe principale d’une boîte flexible, on utilisera la propriété justify-content.
Propriétés raccourcies
La propriété place-items est une propriété raccourcie qui synthétise align-items et justify-items. place-self est une propriété raccourcie qui synthétise align-self et justify-self.
Centrer un objet sur une zone
En combinant les propriétés align-``* et justify-*, on peut facilement centrer un objet sur sa zone de grille.
.wrapper { display: grid; grid-template-columns: repeat(4, 1fr); grid-gap: 10px; grid-auto-rows: 200px; grid-template-areas: ". a a ." ". a a ."; } .item1 { grid-area: a; align-self: center; justify-self: center; }
<div class="wrapper"> <div class="item1">Objet 1</div> </div>
Aligner les pistes d’une grille sur l’axe de bloc
Si on a des pistes qui n’occupent pas tout l’espace du conteneur, on pourra aligner les pistes au sein du conteneur. Là aussi, on peut obtenir cet alignement sur l’axe des colonnes et l’axe des lignes : align-content permet d’aligner les pistes selon l’axe des colonnes et justify-content permettant d’aligner sur l’axe en ligne.
La propriété place-content est une propriété raccourcie pour align-content et justify-content.
Les valeurs disponibles pour align-content, justify-content et place-content sont :
normal
start
end
center
stretch
space-around
space-between
space-evenly
baseline
first baseline
last baseline
Dans l’exemple qui suit, on a un conteneur qui mesure 500 pixels de haut sur 500 pixels de large. On définit trois pistes de ligne et trois pistes de colonnes qui mesurent chacune 100 pixels et avec une gouttière de 10 pixels. On a donc un espace disponible dans le conteneur dans chaque direction.
La propriété align-content s’applique sur le conteneur de la grille car elle porte sur l’ensemble de la grille. Pour une disposition en grille, la valeur par défaut est start : cela indique que les pistes commencent à partir du coin en haut à gauche de la grille.
Alignement par défaut
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3,100px); height: 500px; width: 500px; grid-gap: 10px; grid-template-areas: "a a b" "a a b" "c d d"; } .item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Utiliser align-content: end
Si on ajoute align-content avec la valeur end sur le conteneur, les pistes seront déplacées à la fin du conteneur selon l’axe des colonnes.
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3,100px); height: 500px; width: 500px; grid-gap: 10px; grid-template-areas: "a a b" "a a b" "c d d"; align-content: end; } .item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Utiliser align-content: space-between
Pour cette propriété, on peut également utiliser des valeurs qu’on manipule avec les boîtes flexibles : space-between, space-around et space-evenly qui permettent de répartir l’espace. Si on utilise align-content avec space-between pour notre exemple, on voit alors que les éléments sont espacés de façon équitable.
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3,100px); height: 500px; width: 500px; grid-gap: 10px; grid-template-areas: "a a b" "a a b" "c d d"; align-content: space-between; } .item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
On notera qu’en utilisant ces valeurs pour répartir l’espace, cela peut agrandir les objets de la grille. Si un objet s’étale sur plusieurs pistes, un espace sera ajouté entre chaque piste afin que l’objet qui doit être agrandi puisse absorber cet espace. Aussi, si vous choisissez d’utiliser ces valeurs, assurez-vous que le contenu des pistes puisse absorber cet espace supplémentaire ou que les propriétés d’alignement les renvoient au début de la piste plutôt que de les étirer.
Dans l’image qui suit, on a a placé une grille en utilisant align-content: start et une autre grille qui utilise align-content: space-between. On peut voir la façon dont les objets 1 et 2 (qui s’étalent sur deux lignes) ont gagné en hauteur pour combler l’espace entre les pistes.
Justifier les pistes sur l’axe des lignes
Sur l’axe des lignes, on peut utiliser justify-content de la même façon qu’on utilisait align-content pour l’axe des colonnes.
Avec le même exemple, on utilise justify-content avec la valeur space-around. Là encore, les pistes qui s’étalent sur plus d’une colonne gagnent en largeur.
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3,100px); height: 500px; width: 500px; grid-gap: 10px; grid-template-areas: "a a b" "a a b" "c d d"; align-content: space-between; justify-content: space-around; } .item1 { grid-area: a; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
Alignement et marges automatiques
Pour aligner les objets dans une zone, on peut également utiliser des marges automatiques. Si vous avez déjà utiliser auto pour les marges droite et gauche d’un conteneur de bloc, vous savez qu’une telle marge absorbe l’espace disponible. En utilisant auto pour les deux côtés, le bloc est contraint au milieu car les deux marges occupent le plus d’espace possible.
Dans l’exemple qui suit, pour l’objet 1, on utilise une marge à gauche avec auto. On peut alors voir le contenu poussé à droite de la zone (la marge à gauche occupant le plus d’espace possible).
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3,100px); height: 500px; width: 500px; grid-gap: 10px; grid-template-areas: "a a b" "a a b" "c d d"; } .item1 { grid-area: a; margin-left: auto; } .item2 { grid-area: b; } .item3 { grid-area: c; } .item4 { grid-area: d; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> </div>
On peut voir comment l’objet est aligné grâce à l’outil de mise en évidence des grilles dans Firefox.
L’alignement et les modes d’écriture
Dans tout ces exemples, nous avons travaillé en français ou en anglais, des langues qui s’écrivent de gauche à droite. Cela signifie que les lignes de début de notre grille étaient situées en haut et à gauche lorsqu’on raisonnait avec des directions physiques.
Les spécifications pour les grilles CSS et les boîtes flexibles sont conçues pour fonctionner avec les différents modes d’écriture. Cela signifie que si on travaille avec une langue qui s’écrit de droite à gauche (comme l’arabe), le début de la grille serait en haut à droite. Cela signifie également que la valeur par défaut justify-content: start placerait les pistes du côté droit de la grille. En revanche, si on utilise les marges automatiques avec margin-right ou margin-left ou si on utilise le positionnement absolu avec les valeurs top, right, bottom et left, on ne tiendra pas compte des modes d’écritures. Dans le guide suivant, nous verrons plus en détails comment les grilles et l’alignement interagissent avec les modes d’écriture. Cet aspect est fondamental si vous souhaitez développer des sites qui puissent être affichés dans plusieurs langues ou si vous souhaitez mélanger certaines langues ou modes d’écriture pour une application.
—
Les grilles CSS, les valeurs logiques et les modes d’écriture
Dans les articles précédents, nous avons évoqué un aspect important de la disposition en grille : la prise en charge des différents modes d’écriture. Dans ce guide, nous nous intéresserons plus particulièrement à cette fonctionnalité ainsi qu’aux autres méthodes modernes de disposition. Cela sera également l’occasion d’en apprendre plus sur les modes d’écritures et la notion de propriété logique/physique.
Les propriétés logiques, les propriétés physiques et les valeurs
CSS possède de nombreux mots-clés qui permettent de positionner physiquement les éléments : left, right, top, bottom… Si on positionne un élément de façon absolue, on utilisera ces mots-clés physiques comme valeurs pour indiquer le décalage de l’élément. Dans le fragment de code suivant, l’élément est décalé de 20 pixels depuis le haut du conteneur et de 30 pixels depuis le bord gauche du conteneur.
.container { position: relative; } .item { position: absolute; top: 20px; left: 30px; }
<div class="container"> <div class="item">Item</div> </div>
On rencontre également ces mots-clés physiques avec text-align: right afin d’aligner le texte à droite. Il existe aussi des propriétés physiques en CSS. On ajoute des marges, du remplissage, des bordures grâces à cs propriétés physiques comme margin-left, padding-left, etc.
On qualifie ces propriétés de physiques car elles concernent l’écran qu’on regarde : la gauche sera toujours la gauche, quelle que soit la direction du texte.
Cela peut devenir un problème lorsqu’on développe un site qui doit fonctionner avec plusieurs langues dont certaines sont écrites de droite à gauche et non de gauche à droite. Les navigateurs savent plutôt bien gérer les différentes directions d’écriture. Dans l’exemple qui suit, on a deux paragraphes. Pour le deuxième, aucune propriété text-align n’est utilisée, alors que pour le second, on utilise text-align avec left et on ajoute dir="rtl" sur l’élément HTML ce qui a pour effet de changer la direction d’écriture. On peut voir que, dans le second paragraphe, la direction change et le texte est écrit de droite à gauche. Dans le premier cependant, avec text-align value: left, l’alignement reste à gauche.
Cela illustre un problème fréquent avec les propriétés et valeurs physiques en CSS : elles empêchent le navigateur de passer correctement d’un mode d’écriture à l’autre.
Les propriétés et valeurs logiques
Les propriétés et les valeurs logiques n’émettent pas d’hypothèse quant à la direction du texte. C’est pour cette raison, qu’avec les grilles CSS, on utilise le mot-clé start lorsqu’on souhaite aligner quelque chose au début du conteneur. Quand on travaille en français ou en anglais, start correspondra à la gauche mais ce n’est pas nécessairement toujours le cas, start ne correspond pas à une position physique.
L’axe de bloc et l’axe en ligne
Lorsqu’on commence à travailler avec les propriétés logiques plutôt qu’avec les propriétés physiques, on cesse de voir le monde comme un espace qui va de gauche à droite et de haut en bas. Il faut de nouveaux axes de références : l’axe de bloc (block axis en anglais) et l’axe en ligne (inline axis). Le premier est l’axe orthogonal au sens d’écriture et le second est l’axe dans lequel on écrit. Ces axes logiques sont très utiles et on comprend mieux leurs rôles sur la grille.
Les modes d’écriture CSS
Nous allons ici aborder une autre spécification que nous allons utiliser dans nos exemples : la spécification CSS sur les modes d’écriture (CSS Writing Modes). Cette spécification régit comment les différents modes d’écriture peuvent être utilisés en CSS, pas seulement pour prendre en charge différentes langues mais aussi pour créer des effets artistiques. Nous allons utiliser la propriété writing-mode afin de modifier le mode d’écriture appliqué à la grille pour observer comment fonctionnent les valeurs logiques. Si vous souhaitez approfondir ces notions autour des modes d’écriture, vous pouvez consulter l’article CSS Writing Modes (en anglais) écrit par Jen Simmons.
writing-mode
Les modes d’écriture ne se limitent pas à l’écriture de droite à gauche ou de gauche à droite, la propriété writing-mode nous permet d’afficher du texte dans plusieurs directions. La propriété writing-mode peut prendre les valeurs suivantes :
horizontal-tb
vertical-rl
vertical-lr
sideways-rl
sideways-lr
Sur le Web, c’est la valeur horizontal-tb qui est la valeur par défaut pour le texte. C’est dans cette direction que vous lisez cet article. Les autres valeurs changeront la façon dont le texte est écrit sur le document et correspondent aux modes d’écriture utilisés dans d’autres langues. Dans l’exemple qui suit, on a deux paragraphes, le premier utilise la valeur par défaut horizontal-tb et le second utilise la valeur vertical-rl. Dans ce deuxième mode, le texte est toujours écrit de gauche à droite mais la direction du texte est verticale. Dans ce deuxième paragraphe, l’axe en ligne (inline) est donc l’axe vertical.
<div class="wrapper"> <p style="writing-mode: horizontal-tb">Mon mode d'écriture est celui par défaut <code>horizontal-tb</code></p> <p style="writing-mode: vertical-rl">Moi je suis écrit avec <code>vertical-rl</code></p> </div>
La gestion des modes d’écriture avec une grille
Si on reprend l’exemple avec la grille, on comprend mieux l’effet du changement du mode d’écriture qui change les axes logiques.
Mode d’écriture par défaut
Dans le prochain exemple, la grille possède trois colonnes et deux lignes. Cela signifie qu’il y a trois pistes qui traversent l’axe de bloc. Avec le mode d’écriture par défaut, la grille commence par placer les objets en haut à gauche en remplissant les trois cellules sur la première ligne avant de passer à la suivante, en formant une nouvelle ligne, etc.
.wrapper { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(2, 100px); grid-gap: 10px; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> <div class="item5">Objet 5</div> </div>
Définir writing-mode
Si on ajoute writing-mode: vertical-lr au conteneur de la grille, on peut voir que les axes logiques s’appliquent désormais dans une autre direction. L’axe de bloc (aussi appelé l’axe des colonnes pour la grille) s’étend maintenant de gauche à droite et l’axe en ligne court verticalement.
.wrapper { writing-mode: vertical-lr; display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(2, 100px); grid-gap: 10px; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> <div class="item4">Objet 4</div> <div class="item5">Objet 5</div> </div>
L’utilisation de valeurs logiques pour l’alignement
Dans les exemples précédents, on a vu comment les axes de bloc et en ligne pouvaient changer de direction, nous allons voir maintenant comment tirer partir des valeurs logiques des propriétés d’alignement.
Dans le prochain exemple, on aligne des objets dans une grille pour laquelle writing-mode: vertical-lr. Les valeurs start et end fonctionnent de la même façon qu’avec le mode d’écriture par défaut mais, parce qu’elles sont logiques, on voit que la grille est bien renversée.
.wrapper { writing-mode: vertical-lr; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 100px); grid-gap: 10px; } .item1 { grid-column: 1 / 4; align-self: start; } .item2 { grid-column: 1 / 3; grid-row: 2 / 4; align-self: start; } .item3 { grid-column: 3; grid-row: 2 / 4; align-self: end; justify-self: end; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> </div>
Si vous souhaitez voir l’effet obtenu avec une écriture verticale de haut en bas et de droite à gauche, il suffit de passer de vertical-lr à vertical-rl pour changer de mode d’écriture.
Le placement automatique et les modes d’écriture
On a vu dans l’exemple précédent que lorsqu’on changeait de mode d’écriture, cela changeait également la direction selon laquelle les éléments étaient placés sur la grille. Par défaut, les éléments sont placés en progressant sur l’axe en ligne, jusqu’à la fin de la ligne, une nouvelle ligne est ensuite créée si besoin mais cette ligne ne progresse pas nécessairement de gauche à droite.
Le placement sur les lignes et les modes d’écriture
Il faut garder à l’esprit que lorsqu’on place des objets sur les lignes, la ligne 1 sera toujours la ligne de départ, quel que soit le mode d’écriture et la ligne -1 sera toujours la ligne de fin.
Dans l’exemple suivant, on a une grille avec la direction ltr et on positionne trois objets en utilisant le placement sur les lignes.
L’objet 1 commence à la colonne 1 et occupe une piste
L’objet 2 commence à la colonne -1 et occupe -3 pistes
L’objet 3 commence à la colonne 1 et s’étend jusqu’à la troisième colonne.
Placement sur les lignes pour du texte de gauche à droite
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, 100px); grid-gap: 10px; } .item1 { grid-column: 1 ; } .item2 { grid-column: -1 / -3; } .item3 { grid-column: 1 / 3; grid-row: 2; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> </div>
Placement sur les lignes pour du texte de droite à gauche
Si on ajoute alors la propriété direction avec la valeur rtl pour le conteneur de la grille, la colonne 1 sera la plus à droite et la colonne 1 sera à gauche.
.wrapper { direction: rtl; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, 100px); grid-gap: 10px; } .item1 { grid-column: 1 ; } .item2 { grid-column: -1 / -3; } .item3 { grid-column: 1 / 3; grid-row: 2; }
<div class="wrapper"> <div class="item1">Objet 1</div> <div class="item2">Objet 2</div> <div class="item3">Objet 3</div> </div>
On voit ici que si on change la direction du texte pour la page ou pour une partie de la page : la disposition change selon lees numéros de lignes. Si on ne veut pas que les lignes bougent, on pourra utiliser des lignes nommées pour éviter cet effet.
L’étrange ordre des valeurs pour grid-area
La propriété grid-area permet d’indiquer les quatre lignes qui définissent une zone. Lorsqu’on apprend à utiliser cette propriété, on se surprend à voir que les quatre valeurs ne suivent pas le même ordre que celui utilisé par les propriétés raccourcies pour les marges (pour celles-ci, les valeurs suivent le sens horaire : haut, droit, bas, gauche).
Pour les valeurs de grid-area, l’ordre est le suivant :
grid-row-start
grid-column-start
grid-row-end
grid-column-end
Si on transpose ces valeurs à un système d’écriture de gauche à droite, cela correspond aux valeurs physiques suivantes :
top
left
bottom
right
Ce qui correspond… au sens anti-horaire ! L’ordre est l’inverse de celui utilisé pour les marges et le remplissage. Pour comprendre, mieux vaut voir la propriété grid-area comme une propriété logique qui fonctionne selon les axes de bloc et en ligne : on commence donc avec les deux lignes de départ puis les deux lignes d’arrivée. Cet ordre est plus « logique » !
Utiliser des modes d’écriture hybrides et les grilles CSS
Les modes d’écritures permettent d’afficher les documents en respectant les règles d’affichage de la langue utilisé. On peut également les utiliser afin de créer des effets stylistiques. Dans l’exemple ci-après, on a une grille avec du texte et des liens qui seront affichés verticalement, à côté du texte.
.wrapper { display: grid; grid-gap: 20px; grid-template-columns: 1fr auto; font: 1em Helvetica, Arial, sans-serif; } .wrapper nav { writing-mode: vertical-lr; } .wrapper ul { list-style: none; margin: 0; padding: 1em; display: flex; justify-content: space-between; } .wrapper a { text-decoration: none; }
<div class="wrapper"> <div class="content"> <p>Turnip greens yarrow ricebean rutabaga endive cauliflower sea lettuce kohlrabi amaranth water spinach avocado daikon napa cabbage asparagus winter purslane kale. Celery potato scallion desert raisin horseradish spinach carrot soko. Lotus root water spinach fennel kombu maize bamboo shoot green bean swiss chard seakale pumpkin onion chickpea gram corn pea. Brussels sprout coriander water chestnut gourd swiss chard wakame kohlrabi beetroot carrot watercress. Corn amaranth salsify bunya nuts nori azuki bean chickweed potato bell pepper artichoke.</p> <p>Nori grape silver beet broccoli kombu beet greens fava bean potato quandong celery. Bunya nuts black-eyed pea prairie turnip leek lentil turnip greens parsnip. Sea lettuce lettuce water chestnut eggplant winter purslane fennel azuki bean earthnut pea sierra leone bologi leek soko chicory celtuce parsley jícama salsify.</p> </div> <nav> <ul> <li><a href="">Lien 1</a></li> <li><a href="">Lien 2</a></li> <li><a href="">Lien 3</a></li> </ul> </nav> </div>
Les valeurs physiques et les grilles CSS
On rencontre souvent les propriétés physiques lorsqu’on construit un site web et, bien que la grille et les propriétés logiques permettent de respecter les modes d’écriture, il existe certains effets qui ne peuvent être obtenus qu’avec des propriétés et des valeurs physiques. Dans le guide sur l’alignement des boîtes et les grilles, nous avons vu comment utiliser les marges automatiques sur les zones d’une grille. Utiliser les marges automatiques pour contraindre le placement d’un élément est une astuce qu’on rencontre aussi avec les boîtes flexibles mais cela couple la disposition avec l’espace physique.
Si on utilise le positionnement absolu dans une zone d’une grille, là encore, on utilisera des décalages physiques pour décaler l’élément au sein de la zone. Dans ces cas, il faut être conscient du couplage qu’on ajoute avec l’espace physique et comprendre qu’il faudra adapter la feuille de style si on veut par exemple passer d’un mode ltr à un mode rtl.
Utiliser les propriétés logiques partout
Les nouvelles méthodes de disposition, comme les grilles, permettent d’employer les valeurs logiques afin de placer les éléments. Cependant, dès qu’on combine ces valeurs avec des propriétés physiques, il faut maintenir ces dernières lorsque le mode d’écriture change.
La spécification sur les propriétés logiques en CSS vise à résoudre ce problème. Nous pourrons peut-être utiliser demain des équivalents logiques pour chacune des propriétés physiques telles que margin-left et margin-right. Firefox a déjà implémenté ces propriétés logiques et vous pouvez les y tester. En utilisant les grilles et en manipulant l’axe de bloc et l’axe de ligne, vous saurez également comment fonctionnent ces propriétés logiques à venir.
—
Les grilles CSS et l’accessibilité
Pour celles et ceux qui étaient présents aux premières lueurs du Web, les grilles CSS peuvent rappeler l’âge sombre où les tableaux HTML étaient utilisés pour la mise en forme des pages et où les cellules étaient utilisées pour diviser le contenu. Cette approche avait quelques avantages par rapport au positionnement CSS apparu après : on pouvait tirer parti de l’alignement et des colonnes créées dans un tableau. Il y a toutefois un inconvénient majeur : la mise en forme est fortement couplée à la structure du document, entraînant certains problèmes d’accessibilité. On pouvait par exemple découper le contenu dans le tableau afin d’obtenir la mise en forme souhaitée mais la structure de la page n’avait plus aucun sens lorsqu’elle était lue par un lecteur d’écran.
Aux débuts de CSS, on évoquait souvent CSS comme un outil pour séparer distinctement la mise en forme d’une part et le contenu du document d’autre part. L’objectif ultime était alors de pouvoir créer un document sémantique et structuré correctement puis appliquer une feuille de style CSS afin de créer la disposition voulue. Des sites tels que CSS Zen Garden montrent comment obtenir différents styles grâce à CSS à partir d’un même document HTML.
Les grilles CSS n’ont pas les mêmes problèmes que les tableaux : la structure de la grille est bien définie dans la feuille de style et pas dans le document. Si nécessaire, on peut ajouter un élément sans rôle sémantique. En théorie, une grille CSS nous aide à obtenir cette séparation conceptuelle entre la forme (le code CSS) et le sens (le document HTML) mais est-il possible d’aller trop loin avec cette idée ? Est-ce que les grilles CSS peuvent causer des problèmes d’accessibilité ?
Réordonner le contenu dans une grille CSS
Au fur et à mesure de ces articles, nous avons vu que les grilles CSS nous permettent de réordonner le contenu d’une page de différentes façons. On peut utiliser la propriété order afin de modifier la façon dont les éléments sont placés automatiquement sur la grille. On peut aussi utiliser grid-auto-flow: dense pour que les éléments ne suivent pas l’ordre du DOM afin de réduire les espaces laissés. On peut aussi positionner les éléments sur des lignes ou sur des zones définies, quel que soit leur emplacement dans la structure du document source.
La spécification contient une section qui aborde ce ré-ordonnancement et l’accessibilité. En introduction, on peut lire ce qui est attendu de la part des navigateurs lorsque le contenu est réordonné visuellement avec une grille CSS.
La disposition en grille fournit une grande flexibilité aux auteurs pour replacer le contenu du document. Toutefois, cette flexibilité ne doit pas être utilisée pour pallier à un ordre incorrect du document source. Les propriétés des grilles relatives à l’ordre et au placement n’ont pas d’effet quant aux médias non-visuels (tels que la parole). De la même façon, le ré-ordonnancement visuel des éléments sur la grille n’a pas d’effet sur l’ordre de parcours séquentiel par défaut du document (notamment utilisé pour la navigation au clavier ou le parcours des liens, cf. tabindex).
Si vous réordonnez les éléments du document grâce à une disposition sur une grille, cela ne changera pas l’ordre du contenu lu par un lecteur d’écran ou manipulé par un autre agent utilisateur. Cela ne modifiera pas non plus l’ordre des éléments lorsque ceux-ci sont parcourus au clavier. Une personne utilisant le clavier pourrait ainsi passer d’un coup de la partie haute de la grille à la partie basse si les liens ont été réordonnés.
La spécification prévient les auteurs (c’est-à-dire les développeurs web) et leur indique de ne pas appliquer ce ré-ordonnancement.
Les auteurs doivent utiliser les propriétés d’ordre et de placement uniquement pour des raisons visuelles et non pour réordonner logiquement le contenu. Les feuilles de style qui utilisent ces fonctionnalités afin de réordonner les éléments sur le plan logique ne sont pas considérées comme des feuilles de style conformes.
Quelles sont les implications pratiques lorsqu’on conçoit une disposition avec une grille ?
Un ré-ordonnancement visuel et non logique
La modification d’ordre appliquée par la grille (ou les boîtes flexibles) est uniquement visuelle. C’est toujours le document sous-jacent qui contrôle l’ordre utilisé par les agents utilisateur non-visuels. Voyons comment cela s’applique pour un exemple simple.
Dans cet exemple, on utilise une grille pour organiser un ensemble de boîtes qui contiennent des liens. On utilise les propriétés pour placer les éléments sur des lignes : la première boîte est placée sur la deuxième ligne. Visuellement, cette boîte apparaît désormais comme le quatrième élément de la liste. Mais si on utilise la touche tabulation pour naviguer au clavier parmi les liens, c’est toujours ce lien qui est en premier.
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; } .box1 { grid-column: 1; grid-row: 2; }
<div class="wrapper"> <div class="box box1"><a href="">Un</a></div> <div class="box box2"><a href="">Deux</a></div> <div class="box box3"><a href="">Trois</a></div> <div class="box box4"><a href="">Quatre</a></div> <div class="box box5"><a href="">Cinq</a></div> </div>
Pour ce scénario, la spécification indique que, si la boîte 1 doit logiquement être placée ici, il faut alors modifier le document source plutôt que de réordonner les éléments grâce à la grille.
Comment prendre en compte l’accessibilité avec une disposition en grille ?
On voit à partir de la spécification qu’il faut maintenir l’ordre logique du contenu. Quelle approche choisir pendant le développement afin de s’assurer de respecter l’accessibilité pour les utilisateurs et que ceux-ci puissent interagir correctement avec la page, quels que soient les outils utilisés ?
Les grilles et le risque d’aplatir le document à outrance
On peut rencontrer un autre problème avec les grilles CSS (et, dans une moindre mesure, avec les boîtes flexibles) : vouloir aplatir la structure du document. Comme nous avons pu le voir, pour qu’un objet appartienne à la grille, il faut que ce soit un fils direct du conteneur de la grille. Ainsi, si on place un élément <ul> dans une grille, c’est cet ul qui devient un objet de la grille, les éléments <li> qui en dépendent n’en sont pas.
Si la valeur subgrid est implémentée pour la propriété display, on pourra alors indiquer que ces fils participent à la grille en tant que sous-grille. Actuellement, la seule solution à notre disposition est d’utiliser display: contents afin que la boîte générée par l’élément ul disparaisse de la structure graphique. Pour plus d’informations à ce sujet, vous pouvez consulter l’article sur les liens entre les grilles et les autres méthodes de disposition et notamment la section sur display: contents.
Étant donné que la prise en charge de display: contents pour les différents navigateurs est actuellement limitée et que les sous-grilles n’existent pas encore, on peut être tenté d’aplatir la structure du document lorsqu’on utilise les grilles CSS pour créer la disposition d’un document. Par exemple, pour une liste, identifiée sémantiquement comme telle avec ul, on pourrait plutôt utiliser des éléments <div> qui seraient des éléments directement situés sous le conteneur qui a display: grid. Mieux vaut donc être conscient de cette tentation et construire un document sans détricoter la structure. En commençant par créer un document structuré, on se rend plus facilement compte de la sémantique perdue si on retire des éléments pour une simple question visuelle.
Approfondir la question
Il n’existe pas encore beaucoup de contenu relatif à l’accessibilité et au modèle de grille CSS. La plupart des problèmes rencontrés s’approchent de ceux qu’on rencontre avec les boîtes flexibles (qui permettent également de réordonner le contenu avec des propriétés comme flex-direction et order).
Le concept selon lequel l’ordre d’affichage des éléments doit suivre l’ordre des éléments dans le document est décrit dans WCAG Techniques for Success Criteria – Technique C27 (en anglais).
Pour construire votre réflexion sur ce sujet, je vous invite à lire Flexbox & the Keyboard Navigation Disconnect écrit par Léonie Watson. La vidéo de la présentation de Léonie à ffconf est aussi utile pour mieux comprendre comment les lecteurs d’écran utilisent la représentation visuelle des objets en CSS. Adrian Roselli a également publié un article sur l’ordre de la navigation au clavier dans les différents navigateurs bien que cet article ait été rédigé avant l’implémentation des grilles CSS dans Firefox.
—
Les grilles CSS et l’amélioration progressive
Au printemps 2017, on voit pour la première fois une spécification majeure être disponible presque simultanément dans différents navigateurs : les grilles CSS (CSS Grid). Les grilles CSS sont disponibles dans les versions récentes de Firefox, Chrome, Opera, Safari et Edge. Malgré cela, si ces navigateurs récents permettront à la plupart d’entre nous de profiter de ces nouvelles fonctionnalités, il existe d’anciens navigateurs ou d’autres navigateurs qui ne prennent pas en charge ces fonctionnalité. Dans ce guide, nous allons parcourir différentes stratégies pour gérer cette prise en charge.
Les navigateurs qui prennent en charge les grilles CSS
En dehors d’Internet Explorer, les propriétés et valeurs relatives aux grilles CSS ne sont pas préfixées dans Safari, Chrome, Opera, Edge et dans Firefox. Toutes les propriétés et valeurs que nous avons vues dans ce guide fonctionnent de façon interopérable entre ces navigateurs. Cela signifie que si vous écrivez des règles CSS pour paramétrer une grille, le document doit avoir le même rendu dans Firefox, Opera et dans Chrome. Les grilles CSS ne sont plus une spécification expérimentale, elles peuvent donc être utilisées en production.
La situation pour Internet Explorer et Edge
La première implémentation des grilles CSS a eu lieu avec Internet Explorer 10. La première version de la spécification ne contenait alors pas toutes les propriétés et valeurs décrites dans la spécification actuelle. Il existe également des différences importantes entre ce qui est disponible dans IE10 et la spécification actuelle, même si les propriétés et les valeurs se ressemblent à première vue. Cette implémentation initiale est également celle qui est en place dans Edge jusqu’à la version 15.
La version implémentée pour IE/Edge (≤15) est préfixée avec -ms et les propriétés ont les noms suivants :
grid-template-columns est appelée -ms-grid-columns
grid-template-rows est appelée -ms-grid-rows
grid-row-start est appelée -ms-grid-row
grid-column-start est appelée -ms-grid-column
align-self est appelée -ms-grid-row-align
justify-self est appelée -ms-grid-column-align
La version implémentée dans Internet Explorer dispose de propriétés supplémentaires qui ne font pas partie de la nouvelle spécification : -ms-grid-column-span et -ms-grid-row-span. La version implémentée dans IE ne profite pas du placement automatique ou des zones nommées. On peut implémenter certaines grilles simples pour IE10 et jusqu’à Edge 15, grâce à ces propriétés préfixées par -ms. Ces propriétés étant préfixées, elles ne seront pas reconnues (et n’auront aucun effet) pour les navigateurs qui implémentent la spécification actuelle.
L’utilisation d’autoprefixer pour la prise en charge de la grille
L’outil autoprefixer a été mis à jour afin de prendre en charge les versions préfixées par -ms- lorsqu’on utilise les nouvelles propriétés. Par défaut, les préfixes liés à la grille sont désactivés mais vous pouvez les activer avec l’option grid: autoplace.
autoprefixer({ grid: 'autoplace' })
Les préfixes relatifs aux grilles sont désactivés par défaut car certaines propriétés ne peuvent pas être préfixées
Puis-je utiliser les grilles CSS sans danger ?
Comme pour les autres technologies front-end, la décision d’utiliser les grilles CSS se résume souvent au parc de navigateurs utilisés par le public de votre site ou votre application. S’ils ont tendance à utiliser des version à jour de Firefox, Chrome, Opera et Safari, il serait logique de commencer à utiliser les grilles CSS dès que la nouvelle version des navigateurs sera disponible. En revanche, si le marché visé repose sur d’anciens navigateurs, ce n’est peut-être pas le bon choix. Toutefois, je suggèrerai de ne pas prendre les mêmes hypothèses que pour la diffusion des autres spécifications par le passé : le travail d’implémentation et d’homogénéisation réalisés par les différents distributeurs de navigateur pour les fonctionnalités des grilles CSS est sans précédent.
Commencer à utiliser les grilles CSS en production
On notera qu’il n’est pas nécessaire d’avoir une rupture brutale pour utiliser les grilles CSS. On peut commencer par améliorer quelques éléments avec une grille et conserver l’ancienne méthode d’affichage pour les navigateurs historiques. Surcharger ces méthodes historiques avec les grilles fonctionne très bien étant donné la façon dont les grilles interagissent avec ces autres méthodes.
Effectuer la transition depuis une disposition flottante
Jusqu’à présent, pour créer une disposition sur plusieurs colonnes, on a utilisé des dispositions flottantes. Si vous avez un objet qui flotte et que celui-ci est également un objet d’une grille CSS : dans un navigateur qui prend en charge les grilles CSS, le flottement ne sera plus appliqué sur l’objet. En fait, la grille prend le pas sur le flottement. Dans l’exemple qui suit, on a simplement un objet média. Pour un navigateur historique, on utilise float, cependant, on a également défini un conteneur de grille dans lequel on pourra utiliser les propriétés d’alignement disponibles pour les navigateurs qui implémentent les grilles CSS.
Le mode float ne s’applique plus sur l’objet et on peut utiliser la propriété align-self afin d’aligner le contenu vers la fin du conteneur.
* {box-sizing: border-box;} img { max-width: 100%; display: block; } .media { border: 2px solid #f76707; border-radius: 5px; background-color: #fff4e6; max-width: 400px; display: grid; grid-template-columns: 1fr 2fr; grid-template-areas: "img content"; margin-bottom: 1em; } .media::after { content: ""; display: block; clear: both; } .media .image { float: left; width: 150px; margin-right: 20px; } .media .text { padding: 10px; align-self: end; }
<div class="media"> <div class="image"> <img src="http://placehold.it/150x150" alt="placeholder"> </div> <div class="text"> Voici un exemple avec un média. On utilise le flottement pour les anciens navigateurs et une grille pour les nouveaux. </div> </div>
Dans l’image qui suit, on voit à gauche ce qu’on obtient dans un navigateur qui ne prend pas en charge les grilles CSS et à droite le résultat obtenu pour un navigateur qui permet de les utiliser.
Utiliser les requêtes de fonctionnalité (feature queries)
L’exemple que nous venons de voir est très simple et on peut résoudre le problème sans avoir à écrire de code qui gênerait les navigateurs historiques, le code historique ne pose pas non plus de problème pour les navigateurs qui prennent en charge les grilles CSS. Dans la réalité, on fait parfois face à des cas plus complexes.
Un exemple plus complexe
Dans le prochain exemple, nous aurons un ensemble de cartes disposées avec du flottement. On a défini une largeur (width) sur ces cartes afin de pouvoir appliquer le flottement float. Pour créer des espaces entre les cartes, on utilise une marge (margin) sur les objets puis une marge négative sur le conteneur.
.wrapper ul { overflow: hidden; margin: 0 -10px; padding: 0; list-style: none; } .wrapper li { float: left; width: calc(33.333333% - 20px); margin: 0 10px 20px 10px; }
<div class="wrapper"> <ul> <li class="card"> <h2>Un</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Deux</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Trois</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Quatre</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Cinq</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Six</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> </ul> </div>
Dans la capture qui suit, on voit un problème classique qui est causé par les dispositions flottantes : si on ajoute du contenu à l’une des cartes, la disposition est chamboulée.
Pour gérer les anciens navigateurs dans une certaine mesure, on peut indiquer une hauteur minimale pour les boîtes avec min-height et espérer que les éditeurs n’ajouteront pas trop de contenu dans chaque boîte…
Voyons comment améliorer cette disposition avec une grille : on transforme l’élément <ul> en un conteneur de grille avec trois pistes en colonne. Malheureusement, la largeur qu’on avait affectée aux éléments de la liste s’applique toujours et désormais, chaque élément de la liste occupe uniquement un tiers de la piste correspondante.
Si on réinitialise la largeur avec auto, on n’aura plus le résultat souhaité dans les anciens navigateurs. Il faut donc trouver un moyen de définir la largeur pour les anciens navigateurs et de supprimer la largeur quand le navigateur prend en charge les grilles CSS. Grâce aux requêtes de fonctionnalité CSS, on peut le faire directement en CSS.
Une solution avec les requêtes de fonctionnalité
Les requêtes de fonctionnalité ressemblent beaucoup aux requêtes de média qu’on utilise pour créer des dispositions adaptatives. Ici, plutôt que de vérifier la largeur de la zone d’affichage ou telle caractéristique du navigateur ou de l’appareil, on vérifie la prise en charge d’une propriété CSS avec une certaine valeur grâce à une règle @supports. À l’intérieur de cette requête, on peut écrire le CSS nécessaire pour obtenir la nouvelle disposition et retiré tout ce qui est nécessaire pour l’ancienne mise en forme.
@supports (display: grid) { .wrapper { // ajouter les règles qu'on souhaite // pour les navigateurs qui prennent // en charge les grilles } }
La prise en charge des requêtes de fonctionnalité par les différents navigateurs est excellente. Tous les navigateurs qui prennent en charge la nouvelle spécification pour les grilles CSS supportent aussi les requêtes de fonctionnalité. On peut donc les utiliser pour résoudre le problème précédent pour améliorer la disposition flottante.
On utilise donc @supports pour vérifier la prise en charge de display: grid;, ensuite on indique que <ul> est le conteneur de la grille, on définit la largeur et min-height avec auto pour les éléments <li>. On retire également les marges, les marges négatives et on remplace l’espacement avec la propriété gap. Cela signifie qu’il n’y aura pas de marge finale sur la dernière ligne de boîtes. La disposition fonctionne également désormais lorsqu’une carte possède plus de contenu qu’une autre.
.wrapper ul { overflow: hidden; margin: 0 -10px; padding: 0; list-style: none; } .wrapper li { float: left; width: calc(33.333333% - 20px); margin: 0 10px 20px 10px; } @supports (display: grid) { .wrapper ul { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px; margin: 0; } .wrapper li { width: auto; min-height: auto; margin: 0; } }
<div class="wrapper"> <ul> <li class="card"> <h2>Un</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Deux</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Trois</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Quatre</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Cinq</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Six</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> </ul> </div>
Surcharger les autres valeurs pour display
Étant donné ces problèmes pour créer des grilles d’objets avec du flottement, il est probable que nous aurions choisi un autre méthode initialement, par exemple display: inline-block.
Là encore, on peut utiliser les requêtes de fonctionnalité pour surcharger display: inline-block. Ici aussi, il n’est pas nécessaire de tout surcharger. Pour les éléments concernés par inline-block, ils deviendront des objets de la grille et inline-block ne s’appliquera plus. Dans l’exemple qui suit, on utilise la propriété vertical-align sur les éléments lorsqu’on utilise le mode inline-block, cette propriété n’étant pas appliquée aux éléments d’une grille, elle est ignorée lorsque l’élément devient un objet de la grille.
.wrapper ul { margin: 0 -10px; padding: 0; list-style: none; } .wrapper li { display: inline-block; vertical-align: top; width: calc(33.333333% - 20px); margin: 0 10px 20px 10px; } @supports (display: grid) { .wrapper ul { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px; margin: 0; } .wrapper li { width: auto; margin: 0; } }
<div class="wrapper"> <ul> <li class="card"> <h2>Un</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Deux</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Trois</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Quatre</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Cinq</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> <li class="card"> <h2>Six</h2> <p>On peut utiliser la grille CSS pour surcharger d'anciennes méthodes.</p> </li> </ul> </div>
Ici aussi, il faut reparamétrer la largeur de l’élément puis améliorer les autres propriétés. Dans cet exemple également on a utilisé grid-gap plutôt que des marges et des marges négatives pour créer les « gouttières ».
Comment la spécification gère-t-elle cette surcharge ?
La spécification sur les grilles CSS détaille comment on peu surcharger le comportement de certaines propriétés lorsqu’un élément devient un objet d’une grille. Les sections principales sur ce sujet sont :
La création de conteneurs de grille (Establishing Grid Containers)
Les objets de la grille (Grid Items)
L’affichage d’un objet de la grille (Grid Item Display)
Ce comportement est détaillé dans la spécification et on peut donc l’utiliser pour surcharger les règles utilisées pour les navigateurs qui ne prennent pas en charge les grilles CSS. Ce que nous avons appliqué n’est pas une bidouille, on tire simplement parti de l’interaction entre les différents modes de disposition, tel que décrit dans la spécification.
La disposition sur plusieurs colonnes
Il est aussi possible de partir d’une disposition sur plusieurs colonnes car les propriétés column-* ne s’appliquent pas sur un conteneur de grille.
—
extrait de : https://www.creativebloq.com/advice/a-comprehensive-guide-to-using-css-grid
What is CSS Grid?
With CSS Grid, designers can create completely different device-specific layouts in pure CSS
CSS Grid is an extremely powerful tool for element layout. It introduces unprecedented flexibility in layout, using just pure CSS and without absolutely positioning elements (a technique that can lead to many problems). CSS Grid enables us to achieve extremely diverse and device-specific layouts from the same exact HTML markup.
We no longer have to rely on hacks, absolute positioning nor JavaScript DOM manipulation to realise dynamic, shape-shifting layouts. CSS Grid gives designers a blank canvas to create whatever layouts they desire without having to worry about how to achieve it, ushering in a new era of web design and development with freedom from the CSS limitations and workarounds of the past.
How to define the Grid
In order to create a grid within a container it must be given the CSS property display: grid. The number of columns and rows are determined by the number of space-separated sizes assigned to grid-template-columns and grid-template-rows respectively.
Sizes can be any valid CSS unit such as px or vw, or the auto keyword that enables columns or rows to stretch across available space. For instance, grid-template-columns: 10px auto leads to a 10px column followed by a second column that fills all available space.
Grid also uses a ‘fractional’ unit fr that causes any remaining space to be distributed to columns or rows based on the ratios of these units. grid-template-rows: 1fr 2fr creates two dynamic rows with the second twice the size of the first, while grid-template-columns: 1fr 1fr 1fr 1fr defines four equal-sized columns. The latter can be simplified using the new repeat() function to grid-template-columns: repeat(4, 1fr).
Grid with equally sized cells resulting from equal-ratio, dynamic-width columns and 75px tall rows
A grid can therefore be created inside a container of class grid with four equally sized, dynamic columns and four 75px tall rows (as shown above) using:
.grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 75px); }
Complex grids with unequal sized cells can be created by combining the different units mentioned earlier. We can also use the minmax() function to define the minimum and maximum sizes of dynamic columns and rows. Hence, grid-template-rows: 40px 2fr repeat(2, minmax(75px, 1fr)) leads to four rows with the first 40px tall, the other three stretched over remaining space in a 2:1:1 ratio, and the last two having a minimum height of 75px, which sets the minimum height of the second row to 150px.
Once a grid is created, grid lines, represented by dotted lines in the images, are automatically numbered from the top for rows or from the left for columns. The lines are also given a second, negative number relative to their index from the bottom for rows or from the right for columns.
For instance, the first dotted vertical line on the left in the grids above is 1 and -5, and the third line is 3 and -2. These numbers can be used as the boundary lines of items placed in the grid. The grid lines can also be named by adding a string between square brackets in the property declarations, e.g. grid-template-rows: [1st] 1fr [second-line] 1fr [last].
Grid with minimum and maximum heights created using a combination of px and fr units and the minmax() function
Similar to Flexbox(opens in new tab), the horizontal and vertical position of items placed in the grid can be controlled by setting justify-items and align-items respectively, to start, center, end or stretch.
The same is applicable for grid column and row positions within a larger container using justify-content and align-content respectively. Valid options for these properties also include space-between, where extra space is divided between columns/rows, as well as space-around and space-evenly where space is divided evenly between columns/rows with the same or half the amount of space on the ends respectively. We can also define align-content and justify-content (in that order) using place-content, and align-items and justify-items using place-items.
Positioning items using line numbers
To place an item in the grid we can set its grid-column-start and grid-column-end properties to the vertical line numbers between which the item should be stretched. For rows, the properties are grid-row-start and grid-row-end – and of course the numbers refer to the horizontal lines.
Items can be contained within a single grid cell or stretched across multiple columns and grids
We could also make use of the shorthands grid-column and grid-row, by setting them to only the starting grid line, causing the item to automatically stretch to the next grid line only. As per the image above, using these methods, item1 can be placed between vertical lines 2 and 4 and horizontal lines 3 and -1 (last line or first from bottom), and item2 from vertical line 3 and horizontal line 1 to the next grid lines using:
#item1 { grid-column-start: 2; grid-column-end: 4; grid-row-start: 3; grid-row-end: -1; } #item2 { grid-column: 3; grid-row: 1; }
To simplify further, the declarations grid-column-start: 2 and grid-column-end: 4 can be combined together as grid-column: 2 / 4, with the same applicable for rows using grid-row.
The caveat with using these placement methods is that some of the declarations are somewhat misnomers. For example, grid-column-end: 4 and grid-column: 2 / 4 can be misinterpreted as meaning ‘end item placement in column 4′ and ‘place item in columns 2, 3 and 4′ respectively. This is of course not the case as the numbers represent the grid lines rather than columns. To avoid this potential pitfall, we can declare the starting grid line number and the number of columns or rows the item should span across use the span keyword.
Use the span keyword to determine the number of columns or rows you would like an item to span
Using these methods, we can reposition item1 between horizontal lines 2 and 4 and vertical lines 1 and 2, and item2 starting from vertical line 2 and spanning across three columns and from horizontal line 3 spanning across two rows (as in the image above) using:
#item1 { grid-column: 1; grid-row: 2 / 4; } #item2 { grid-column: 2 / span 3; grid-row: 3 / span 2; }
Believe it or not, item placement can be simplified even further with the property grid-area, which is a shorthand for grid-row-start, grid-column-start, grid-row-end and grid-column-end in that order. If only the first two properties are defined the item will automatically be placed between those lines and the following ones.
This grid property also enables line numbers to be combined with the span keyword. Applying these methods, we can reposition item1 and item2 as such:
#item1 { grid-area: 2 / 1 / span 2 / span 3; } #item2 { grid-area: 4 / 4; }
Positioning items using area names
Although using grid line numbers and the span keyword is a great way of positioning items, there is an even more intuitive and easy way to place items in the grid. It involves using the grid-area and grid-template-areas properties.
To achieve this, each item to be positioned in the grid must first be given a name by setting its grid-area property to a string that can then be included in the grid’s grid-template-areas declaration. It then becomes possible to define grid-template-areas using a visual ‘map’ in which rows are enclosed in quotation marks, with the contents of each grid cell represented by a string pertaining to the grid-area names of the items.
Empty cells are symbolised by a full stop (.) and spaces signify vertical grid lines. The rows can be placed on new lines to provide a visual representation of the grid, as follows:
#item1 { grid-area: item1; } #item2 { grid-area: item2; } .grid { grid-template-areas: ". . . ." ". . . item1" "item2 item2 item2 item1" "item2 item2 item2 ."; }
How to create a responsive layout using CSS Grid
CSS Grid can be used with media queries to restructure items on different screen sizes without changing the markup. Item shape, size and position can all be completely changed, thus leading to a truly responsive and highly customised layout.
Figure 1
Let’s say we have a list of elements generated from this HTML markup (figure 1):
<div class="grid"> <div class="header"></div> <div class="menu"></div> <div class="hero"></div> <div class="main"></div> <div class="banner"></div> <div class="extra"></div> <div class="image"></div> </div>
Figure 2
Using what we have learned about Grid so far we can apply styles for screens that are wider than 720px, using a media query (figure 2):
@media (min-width: 721px) { .header { grid-area: header; } .menu { grid-area: menu; } .hero { grid-area: hero; } .main { grid-area: main; } .banner { grid-area: banner; } .extra { grid-area: extra; } .image { grid-area: image; } .grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: 40px 2fr repeat(4, 1fr); grid-template-areas: "header header header header" "hero hero hero hero" "menu main main main" "menu main main main" "menu banner banner banner" "menu extra image image"; } }
Figure 3
We can also easily reposition and resize the items for larger screens that are wider than 1000px using another media query (figure 3):
@media (min-width: 1001px) { .grid { grid-template-areas: "header menu menu menu" "hero hero hero hero" "hero hero hero hero" "main main . image" "main main . extra" "banner banner banner banner"; } }
That’s not all – the number of grid columns and rows can even be changed to make allowances for certain screen sizes, if this is desired, by redefining grid-template-columns and/or grid-template-rows within the media queries.
Overlapping elements can also be achieved using CSS Grid. Multiple items can occupy the same grid cells and hence can overlap with one another, utilising the z-index properties of the items to control the order in which they stack.
Figure 4
For example, we can add a semi-transparent element with the class toolbar inside the grid container and position it in the right-most column so that it overlaps with all the other elements (figure 4):
.toolbar { grid-column: 4; grid-row: 1 / -1; opacity: .85; z-index: 1; }
Figure 5
The final aspect we will discuss is the spacing between columns and rows or gaps (figure 5). Items in the grid can be separated using the grid-column-gap or grid-row-gap properties that set the size of the gap between columns and rows respectively. The shorthand property grid-gap can set both.
CSS Grid fallbacks for older browsers
Laying out CSS Grid properties below mobile properties ensures browsers that still don’t support Grid will ignore it and render the mobile version. We can alternatively add a basic fallback layout using @supports, a query that applies rules based on browser support for a specific CSS feature. We can thus set a fallback layout for screen sizes wider than 720px:
@supports not (display: grid) { @media (min-width: 721px) { .header, .extra { float: left; width: 50%; } } }
If for some reason you need this fallback to be shown for Internet Explorer 10 and 11, which don’t support Grid nor, ironically, the @supports query, you can use a well-known query that applies styles only in IE10 and 11:
@media (min-width: 721px) and (-ms-high-contrast: none), (-ms-high-contrast: active) { .header, .extra { float: left; width: 50%; } }
If you require IE9 and older support, load an additional stylesheet in the HTML with the relevant styles using:
<!--[if IE]><link rel="stylesheet" href="ie.css" /><![endif]-->
CSS Grid resources
CSS tricks to revolutionise your web layouts(opens in new tab)
6 web layout myths busted(opens in new tab)
CSS Grid Layout secrets revealed
—