Blog tech

CSS Grid Layout c'est magique

Rédigé par Victor Darras | 5 mai 2017

CSS Grid c’est magique :’)

Bonjour à tous, aujourd’hui nous allons découvrir ensemble une des plus belles nouveautés de CSS depuis plusieurs années, les Grids.

Si je vous dis que c’est l’une des plus belles nouveautés c’est bien parce qu’on a affaire à un ensemble de propriétés évoluées, qui auront un impact fort sur la lisibilité et la simplicité de nos feuilles de style, et qui révolutionnent de manière très puissante la gestion des positionnements.

CSS Grid layout permet de diviser un élément (en général le document entier) en cellules ou régions utilisables par ses enfants. Nous pouvons ensuite définir des ratios de taille ou de positionnement ainsi qu’une possibilité d’empilement pour ces enfants.

J’en ai déjà un peu parlé dans cet article sur Flexbox mais la gestion des positionnements en CSS a beaucoup évolué depuis leur création.

Nous allons voir ensemble comment créer une structure d’application web puis nous jouerons avec les propriétés plus ou moins connues de Grid layout.

See the Pen CSS Grid experiment by Victor Darras (@victordarras) on CodePen.

Avant d’aller plus loin, n’oublions pas que nous parlons d’un standard très récent (mai 2017) et qu’il n’est disponible que sur les versions les plus récentes des navigateurs les plus populaires :

On ne peut pas dire qu’il existe un équivalent pour les vieux navigateurs. Nous aurions pu faire ce genre de positionnement avec des absolute, des float ou encore des tableaux. Je n’ai donc pas de fallback parfait à vous présenter, il n’y en a pas…

Une structure de page standard

Avant de continuer, nous allons mettre en place un minimum de markup HTML.

Un en-tête, un menu de navigation, un espace libre de contenu et un pied de page. Tous ces éléments seront placés dans un conteneur de page qui fera la taille du viewport.

Premier point à noter, les CSS Grids sont pensées pour avoir un markup le plus clair possible.

Inutile de créer un conteneur pour placer 2 éléments côte à côte comme nous devions le faire avec des systèmes de grilles type Foundation ou Bootstrap. Rappelez-vous l’époque où pour faire ce genre de mise en page nous utilisions sans vergogne une structure de tableau, avec un markup complexe et une lisibilité frisant le ridicule comme :

<!-- Technique à éviter -->
<div class="page">
  <table>
    <thead>
      <tr>
        <th colspan="2">
          <div class="header">Header</div>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <div class="navigation">Navigation</div>
        </td>
        <td>
          <div class="content">Content</div>
        </td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <td colspan="2">
          <div class="footer">Footer</div>
        </td>
      </tr>
    </tfoot>
  </table>
</div>
<!-- Technique toujours à éviter -->

Comme nous avons de la chance de faire du web en 2017 !

<!-- On est mieux là, non ? -->
<div class="page">
  <div class="header">Header</div>
  <div class="navigation">Navigation</div>
  <div class="content">Content</div>
  <div class="footer">Footer</div>
</div>
<!-- Oui, je trouve aussi -->

Pour le moment, tous ces éléments s’affichent les uns sous les autres. Pour commencer à utiliser les CSS Grids nous appelons la propriété display bien connue avec sa nouvelle valeur : grid.

Avec cette règle, à l’instar de Flexbox, nous indiquons au navigateur que tous ses enfants vont hériter du système de grille et donc se comporter comme des cellules. Voyons comment utiliser ces éléments dans un système de grille…

Dans un premier temps stylons les différentes parties pour qu’on puisse aisément les discerner :

.header {
  background: Aquamarine;
}
.sidebar {
  background: Bisque;
}
.content {
  background: Khaki;
}
.footer {
  background: Coral;
}

Maintenant que nos blocs sont bien visibles, définissons les règles de gestion de la grille que nous voulons :

body {
  width: 100vw; /* Equivalent to 100% width of viewport */
  height: 100vh; /* same with height */
  display: grid;
  grid-template-columns: 20vw 1fr;
  grid-template-rows: 10vh 1fr 8vh;
}

Nous forçons la taille de body pour qu’il prenne toute la largeur et la hauteur du viewport (avec 100vh et 100vw), on indique ensuite que c’est cet élément qui constituera la grille avec display: grid.

Vient la partie intéressante de définition des contraintes.

Avec grid-template-columns (attention au s de columns) nous indiquons la taille voulue pour chacune des colonnes de la grille. Pour chaque valeur ajoutée, le navigateur créera une nouvelle colonne à remplir.

Nous aurons donc une première colonne de 20vw de large et une seconde qui prendra l’espace restant grâce à la nouvelle unité fr (fraction) correspondant à un ratio de l’espace restant.

De la même manière nous pouvons ajouter des lignes avec des tailles différentes. Dans cet exemple, la première et dernière ligne feront respectivement 10vh et 8vh ; celle du milieu prendra la taille restante.

Par défaut, chaque région va prendre la première place disponible parmi les cellules définies par notre grille. Ainsi le header se positionne en haut à gauche, suivi de la sidebar en haut à droite. Sur la seconde ligne on trouve le content à gauche et le footer à droite. Évidemment, de cette manière la dernière ligne de grille est vide.

Pratique pour des grilles d’images ou de contenu standard, ce positionnement en flux (les éléments se placent les uns derrière les autres) ne correspond pas à la structure de page que nous voulons, il faut ajouter quelques règles.

.header {
  grid-column: 1 / 2;
  grid-row: 1;
}
.sidebar {
  grid-column: 1;
  grid-row: 2 / span 2;
}
.content {
  grid-column: 2;
  grid-row: 2;
}
.footer {
  grid-column: 2;
  grid-row: 3;
}

Pour chaque région, nous ajoutons donc une règle grid-column qui prendra en argument la position voulue sur la grille.

Pour le header nous lui spécifions de commencer sur la première colonne et de finir sur la deuxième avec grid-column: <start-colunm> / <end-column>.

Avec une technique différente nous spécifions à la sidebar de commencer en ligne 2 et de s’étendre sur 2 régions grâce à span 2.

Pour le content nous voulons qu’il se positionne sur la deuxième colonne, mais seulement sur la 2ème ligne. Pour ça on ajoute une règle grid-row — qui fonctionne de la même manière que son acolyte grid-column — avec une valeur de 2.

Template areas

CSS Grid layout, en plus de nous offrir beaucoup de rigueur dans le positionnement, permet aussi de le rendre plus lisible pour la plupart des cas, notamment pour cet exemple.

Il me semble que le nommage de la grille est adapté à un template fixe comme dans notre exemple mais assez peu adapté à un affichage en flux dynamique où la position de chacun des éléments nous importe peu.

Grâce à la propriété grid-template-areas nous pouvons nommer certaines régions de la grille body. De manière très visuelle, nous représentons et nommons les régions de la grille. On entoure chaque ligne par des " puis, pour chaque colonne on ajoute un espace ou un passage à la ligne (Non compatible avec la syntaxe SASS) :

body {
  display: grid;
  grid-template-columns: 20vw 1fr;
  grid-template-rows: 10vh 1fr 8vh;
  grid-template-areas:
    "header    header"
    "sidebar  content"
    "footer    footer"
    ; /*
      Pas de soucis pour utiliser des
      espaces entre les noms de régions,
      je peux donc les aligner à ma guise.
    */
}

Une fois cette grille renommée nous n’avons plus qu’à réutiliser les régions susnommées avec la propriété grid-area :

.header {
  grid-area: header;
}
.sidebar {
  grid-area: sidebar;
}
.content {
  grid-area: content;
}
.footer {
  /*  Les deux syntaxe peuvent bien sûr être utilisées en même temps */
  grid-column: 2;
  grid-row: 3;
}

Nous arrivons au même résultat mais avec une syntaxe plus accessible bien que très différente de ce à quoi CSS nous avait habitué.

Espacement et marges

Maintenant que nos sections sont correctement positionnées, voyons comment ajouter quelques marges :

body {
  margin: 12px;
  grid-gap: 12px;
}

Grâce à grid-gap nous pouvons définir l’espace qu’il y a entre chacune des régions. J’ajoute un margin identique au conteneur pour visualiser plus facilement les régions et leurs limites. Nous pourrions aussi utiliser indépendamment grid-row-gap ou grid-column-gap qui définissent les espaces entre lignes ou colonnes.

Conclusion

Un article assez court pour des possibilités très étendues, mais c’est ce qui m’a plu avec CSS Grid : sa simplicité de prise en main.

Il est évidemment possible de combiner ces nouvelles propriétés dans des media queries afin de créer des site responsive plus précis et maintenable.

J’imagine que ces nouvelles solutions rendront le positionnement CSS plus simple à tout un chacun.

L’équipe Synbioz.
Libres d’être ensemble.