CSS Grid et le Saint Graal

Un premier article sur la nouvelle spécification CSS Grid Layout. Ire Aderinokun s'attaque au Saint Graal et nous initie aux mystères d'une spécification qui va changer notre façon de travailler!

Par

Le Module CSS Grid Layout, bien que toujours à l’étape Editor’s Draft, est en cours de finalisation. Nous pouvons maintenant l’utiliser dans de nombreux navigateurs pour le tester et relever les éventuels bugs.

CSS Grid Layout est assez complexe, plus encore que Flexbox. Il comporte 17 nouvelles propriétés et introduit pas mal de nouveaux concepts dans notre manière d’écrire CSS. J’ai donc essayé de comprendre cette nouvelle spécification et pour cela je me suis dit que la création du fameux Holy Grail (Saint Graal) était un beau défi.

Qu’est que que le Holy Grail Layout ?

Le Holy Grail est un layout constitué de quatre sections — un header, un footer, et une zone principale comportant deux sidebars, un de chaque côté. La mise en page respecte les règles suivantes :

  • Elle comporte une colonne centrale de largeur fluide et des sidebars de largeur fixe.
  • La colonne centrale doit apparaître en premier dans le markup, avant les deux sidebars mais après le header.
  • Les trois colonnes doivent avoir la même hauteur, indépendamment de leur contenu.
  • Le footer doit toujours se trouver en bas du viewport, même si le contenu ne remplit pas la hauteur du viewport.
  • Le layout doit être responsif, toutes les sections doivent se retrouver sur une seule colonne sur les viewports de dimension réduite.

Le Saint Graal est bien connu pour être difficile à créer en CSS sans aucun tripatouillage.

La solution avec CSS Grid

Voici la solution à laquelle je suis parvenue avec CSS Grid Layout. Tout d’abord, le markup :

<body class="hg">  
  <header class="hg__header">Title</header>
  <main class="hg__main">Content</main>
  <aside class="hg__left">Menu</aside>
  <aside class="hg__right">Ads</aside>
  <footer class="hg__footer">Footer</footer>
</body>  

Et le CSS, qui ne comporte que 31 lignes (dont expansion !) :

.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
    grid-template-columns: 150px 1fr 150px;
    grid-template-rows: 100px 
                        1fr
                        30px;
    min-height: 100vh;
}

@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
        grid-template-columns: 100%;
        grid-template-rows: 100px 
                            50px 
                            1fr
                            50px 
                            30px;
    }
}
Image gif montrant le layout responsif à diverses largeurs d’écran
Le résultat final

Le détail, pas à pas

Comme je l’ai déjà dit, CSS Grid Layout peut être vraiment compliqué. Toutefois, pour créer ce layout, je n’ai utilisé que 4 des 17 propriétés.

  • grid-area
  • grid-template-areas
  • grid-template-columns
  • grid-template-rows

Ma solution au problème du Holy Grail via les propriétés CSS Grid peut être décomposée en cinq étapes.

1. Définir la grille

La première chose à faire est de définir les zones (area) de notre grille (grid), de façon à pouvoir nous y référer lorsque nous créons la grille. Pour cela, nous utilisons la propriété grid-area (zone de la grille).

.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

Puis, avec la propriété grid-template-areas, nous pouvons spécifier le layout de notre grille de manière très intuitive et visuelle. La propriété grid-template-areas prend une liste de chaînes de caractères séparées par un espace. Chaque chaîne de caractères (délimitée par des guillemets) représente une rangée. À l’intérieur de chaque chaîne de caractères, nous avons une liste de zones de notre grille, séparées par un espace. Chaque zone de grille ainsi définie occupe une colonne. Donc si nous voulons qu’une zone couvre deux colonnes, nous la définissons deux fois.

Dans notre layout Holy Grail, nous avons 3 colonnes et 3 rangées. Les rangées Header et Footer occupent chacune 3 colonnes, les autres zones n’occupent chacune qu’une seule colonne.

.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
}

Avec ce markup, nous obtenons le résultat suivant :

Un premier résultat : nos éléments sont placés.

2. Définir la largeur des colonnes

Ensuite, nous voulons définir la largeur des colonnes. Pour ce faire, on utilise la propriété grid-template-columns. Cette propriété prend une liste de largeurs séparées par un espace, une largeur pour chaque colonne de la grille. Comme nous avons trois colonnes dans notre layout, nous devons spécifier trois largeurs.

grid-template-columns: [column 1 width]  [column 2 width]  [column 3 width];  

Pour notre layout, nous voulons que les deux colonnes sidebar fassent 150px de large chacune.

.hg {
  grid-template-columns: 150px  [column 2 width] 150px;
}

Nous voulons également que la colonne du milieu occupe l’espace restant. Pour cela, nous utilisons la nouvelle unité fr. Cette unité représente une fraction de l’espace laissé libre dans la grille. Dans notre cas, ça revient à dire que l’espace est égal à la largeur de la grille moins 300px (la largeur des deux sidebars).

.hg {
    grid-template-columns: 150px 1fr 150px;
}

Une fois définies nos largeurs de colonnes, voici notre résultat intermédiaire :

Nos largeurs de colonnes sont définies.

3. Définir la hauteur des rangées

Dans cette étape, nous allons définir la hauteur des rangées. De la même façon, nous définissons les hauteurs de rangées avec la propriété grid-template-rows. Cette propriété prend une liste de hauteurs séparées par un espace pour chaque rangée de notre grille. Nous pourrions l’écrire sur une seule ligne, mais je trouve que c’est plus clair, et plus joli, de mettre une rangée par ligne :

.hg {
    grid-template-rows: 100px 
                        1fr
                        30px;
}

Et voilà, notre header fait 100px de hauteur, notre footer 30px, et la rangée du milieu (avec le contenu principal et les sidebars) occupe le reste de l’espace disponible dans l’élément .hg.

Nous avons maintenant des rangées de hauteur définie.

Sticky Footer

Dans le layout Holy Grail, le footer doit toujours se trouver en bas du viewport, même si le contenu de la page est minimal. Pour y parvenir, nous pouvons définir que la hauteur minimum de l’élément .hg sera la hauteur du viewport.

.hg {
    min-height: 100vh;
}

Comme nous avons spécifié que la rangée du milieu devra remplir tout l’espace restant, elle s’étire pour remplir l’écran :

Notre footer est en bas de page et la rangée centrale occupe toute la hauteur.

Ajouter de l’adaptabilité

Enfin, nous voulons que notre layout soit responsif. Sur les terminaux de taille réduite, tous les items de la grille devraient être affichés sur une seule colonne, l’un après l’autre. Pour cela, nous devons redéfinir les trois propriétés que nous venons de définir, ’grid-template-areas’, ’grid-template-columns’ et ’grid-template-rows’.

Tout d’abord, nous voulons que tous les items de la grille soient positionnés sur une seule colonne, et dans un ordre donné :

@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
    }
}

Ensuite, nous voulons que tous les items occupent la largeur totale de la colonne :

@media screen and (max-width: 600px) {
    .hg {
        grid-template-columns: 100%;
    }
}

Enfin, nous devons redéfinir les hauteurs de chaque rangée. Toutes les rangées, hormis la rangée main, ont une hauteur définie.

@media screen and (max-width: 600px) {
    .hg {
        grid-template-rows: 100px /* Header */
                            50px /* Navigation */
                            1fr /* Main Content */
                            50px /* Ads */
                            30px; /* Footer */
    }
}
Nos éléments sont empilés sur une seule colonne lorsque la largeur du viewport est inférieure ou égale à 600px.

Voilà, c’est fini ! Vous pouvez consulter une démo ici et la source (NB: il vous faudra sans doute autoriser les fonctionnalités expérimentales de votre navigateur pour les voir).

Compatibilité

Vous pouvez retrouver le détail des navigateurs compatibles sur Can I Use. À ce jour, CSS Grid Layout est supporté par IE 11 et Edge, il est en développement dans les autres navigateurs.


Intéressé par CSS ? Retrouvez une liste des meilleurs articles et ressources du web.

Tous les articles sur CSS parus dans la Cascade.

Tous les articles sur CSS-Grid parus dans la Cascade.

Du même auteur, dans la Cascade :

Comment fonctionne CSS float
Comment fonctionne z-index
Contrôler le modèle de boîte
Cacher des éléments avec CSS
Styler les images non affichées
Sur :not et la spécificité
CSS Grid et le Saint Graal
CSS Initial, Inherit, Unset et Revert

Articles sur les mêmes thèmes dans la Cascade :

In Search of the Holy Grail, l'article de Matthew Levine paru dans A List Apart en 2006


Article original paru le 29 mars 2016 dans Bits of Code.

Sur l’auteur : est UI Designer et Front-End Developer à Lagos, au Nigéria. Son blog Bits of Code s’adresse aux développeurs autodidactes comme elle, elle y explore la théorie cachée derrière les morceaux de code que nous écrivons, afin de mieux comprendre le développement web. On peut la suivre sur Twitter ou sur Github.

Traduit avec l’aimable autorisation de Bits of Code et de l’auteur.
Copyright Bits of Code © 2016.