Grid, or not grid

Après Flex, voilà Grid la seconde technologie que tout développeur web se doit de connaître. Venez apprendre à organiser vos pages simplement en CSS pur !

Auteur :
Jonathan Marco
Difficulté :
Initiation au rêve (débutant)

Bienvenue les cadettes et les cadets ! Dans ce chapitre nous allons parler de Grid ! C'est une technologie complémentaire à Flex qu'on a vu dans un chapitre précédent. Là où Flex est utilisé pour aligner les éléments, Grid permettra une organisation structurelle de ceux-ci.

Les Grid templates

Comme pour Flex, pour organiser vos éléments avec Grid, vous devez indiquer au parent d'utiliser Grid.

section {
    display: grid;
}
Quand on met juste le parent en grid, il ne se passe rien car, par défaut, si on ne détermine pas le nombre de colonnes, il n'y en aura qu'une, et, donc les éléments seront toujours les uns en dessous des autres.

Les templates permettent de définir le nombre et la taille, absolue ou relative, des colonnes et des lignes.

Lorsqu'on écrit le code :

section {
    display: grid;
    grid-template-columns: 100px 100px 100px;
}

... on a trois colonnes, car on a écrit trois valeurs. Chacune fera 100px de large, car c'est la valeur absolue que l'on a déterminée.

Le fonctionnement est le même pour grid-template-rows mais pour les lignes.

Les fractions = fr

Pour éviter d'indiquer une valeur absolue, qui peut être amenée à changer au cours du projet, on va plutôt utiliser la notation en fr. Elle représente une fraction de la grille. Grid va diviser la grille en un certain nombre de fractions et les répartira entre les colonnes selon les valeurs attribuées. Si on écrit :

section {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

Si l'on décompose le fonctionnement, on a les valeurs 1fr 1fr 1fr. Grid va donc diviser la grille en 3 fractions égales : 1 + 1 + 1, puis elle va en donner une à chacune des colonnes. Elles feront donc toutes 1/3 de la largeur de la grille. Si on écrit :

section {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
}

... la première colonne fait la moitié de la grille car elle prend 2/4 des fractions et les deux dernières, 1/4 chacune.

Mélanger les valeurs

On peut aussi mixer les valeurs absolues et les valeurs relatives :

section {
    display: grid;
    grid-template-columns: 1fr 1fr 100px;
}

... avec ce code, la dernière colonne fera toujours 100px de large, et les deux autres prendront la place qui reste et se répartiront équitablement l'espace qui leur est alloué.

Ne pas se répéter = repeat

Quand on a le code suivant : 

section {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

... on peut l'écrire comme ça :

section {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
}

... le premier paramètre est le nombre de fois où l'on répète la valeur en second paramètre.

Aligner

Pour aligner verticalement :

section {
    display: grid;
    grid-template-columns: 2fr 1fr 150px;
    align-items: center;
}

Pour aligner horizontalement :

section {
    display: grid;
    grid-template-columns: 2fr 1fr 150px;
    justify-items: center;
}
Attention, l'alignement horizontal n'est pas justify-content mais justify-items.

Les valeurs possibles pour align-items et justify-items :

  • start
  • end
  • center
  • stretch

Espacer les éléments

On peut ajouter des marges entre les lignes avec row-gap, entre les colonnes column-gap ou entre les deux en même temps gap.

Créer automatiquement les colonnes

Deux autres options très utiles de Grid ce sont : auto-fit et auto-fill. Elles s'utilisent souvent avec minmax.

minmax

Cette fonction va prendre deux paramètres : 

  • min = la valeur minimum de la colonne.
  • max = la valeur prise si on a la place de faire plus que la valeur min.

Exemple :

section {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}

Dans cet exemple, Grid va essayer de créer le plus grand nombre de colonnes possible sur la largeur de l'écran, avec une largeur minimale de 100px pour chacune d'entre elles. Sinon, alors elles seront réparties équitablement avec 1fr pour chacune d'entre elles.

auto-fill

Cette option se basera plutôt sur la valeur "min" de minmax et faire en sorte de créer autant de colonnes que possible sur la largeur de l'écran.

auto-fit

Celle-ci, se basera sur le nombre d'éléments à répartir. Si l'on reprend l'exemple ci-dessus, en changeant auto-fill pour auto-fit :

section {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}

Pour cet exemple, on considère qu'on a un écran de 1920px de large et trois éléments à répartir, chacun fera alors 640px de large.

auto-fit divisera la grille en autant de colonnes qu'il y a d'éléments à répartir, avec comme valeur minimale, la valeur "min" de minmax. Donc si on a 20 éléments à répartir, 1920 divisé par 20 étant égal à 96 et que 96 est inférieur à 100px. Alors le vingtième item ira à la ligne et la largeur de la grille sera réparti en 19 colonnes.

Grid en pratique

Construire la card

La card de notre projet correspond plutôt à un article, car elle a une image d'illustration, un titre et un texte de contenu.

Notre image est purement décorative, elle aura donc un alt (obligatoire) mais vide car elle n'apporte pas d'information.

Le titre est un sous-titre, car le titre principal de la page est "Nos recettes", on utilisera donc un h2.

Pour le paragraphe, je ne mets pas tout le texte prévu dans le code ci-dessous pour éviter de surcharger inutilement le code.

Pour un lien, quand on n'a pas encore de cible à mettre dans le href, il est convenu par défaut de mettre un #.

Ce qui nous donne le code suivant : 

<article>
  <img src="/assets/img/card_meat.jpeg" alt=""/>
  <h2>Le dindon de la farce</h2>
  <p>Zombie ipsum reversus ab viral inferno...</p>
  <a href="#">Voir la recette</a>
</article>

Styliser la card

Le titre est non gras et a une font à 32px. 

main h1 {
    font-size: 2rem;
    font-weight: normal;
    color: white;
}

 La card a une largeur de 360px. Une couleur de fond qu'on récupère sur la maquette. Elle a également des bords arrondis à 8px et une marge interne de 16px. Cette marge interne va poser un problème si on garde le HTML ci-dessus. En effet, si j'ai ce code : 

main nav article {
    width: 22.5rem;
    border-radius: 0.5rem;
    background-color: rgba(205, 255, 176, 0.1);
    color: white;
    padding: 1rem;
}

Le padding sera également autour de la photo, ce qu'on ne souhaite pas. Je vais donc ajouter une div autour des éléments titre, paragraphe et lien pour mettre le padding uniquement autour de ces derniers.

Je peux mettre une div car là, la balise utilisée n'est nécessaire que pour le style. Elle n'a pas de sens sémantique.
<article>
  <img src="/assets/img/card_meat.jpeg" alt=""/>
  <div>
    <h2>Le dindon de la farce</h2>
    <p>Zombie ipsum reversus ab viral inferno...</p>
    <a href="#">Voir la recette</a>
  </div>
</article>

Et je mets le code CSS nécessaire sur la div :

main article div {
    padding: 1rem;
}
Vous noterez que je n'ai pas mis main nav article div pour éviter d'avoir des niveaux de profondeurs trop importants. Ici comme je sais que je n'ai qu'un main je peux me permettre de supprimer le niveau nav. Par contre, je précise toujours article, pour la facilité de lecture afin de toujours savoir dans quel élément principal je me trouve.

Je stylise l'image :

main article img {
    width: 100%;
    border-radius: 0.5rem 0.5rem 0 0;
}

J'ai ajouté également le border-radius sur l'image car sinon j'ai les coins de l'image qui ne sont pas arrondis. Par contre, je ne mets que deux valeurs pour n'avoir que le coin en haut à gauche et en haut à droite d'arrondis et deux zéros.

Quand border-radius a quatre valeurs, la première correspond au coin en haut à gauche et ensuite on tourne dans le sens des aiguilles d'une montre.

Le titre :

main article h2 {
    font-size: 1.5rem;
    font-weight: normal;
}

Le lien :

main article a {
    color: #e5878a;
    display: flex;
    align-items: flex-end;
}

Pour aligner mon lien à droite, je l'ai mis en Flex : alignement = Flex !

cards & grid

Pour la version ordinateur du style, si on veut 3 cards par ligne avec une marge de 16px entre chaque item, le tout centré sur l'écran, on aura alors le code suivant :

main {
    width: fit-content;
    margin: 0 auto;
}

main nav {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
}

J'ai ajouté fit-content à main pour lui dire qu'il fasse la largeur de son contenu et non celui de l'écran, qui est le comportement par défaut des éléments block. 

Je lui ai également ajouté magin: 0 auto, pour le centrer par rapport à l'écran, ce qui est pratique si l'on veut aligner un élément solitaire qui n'a pas de parents (donc pas possible de faire du Flex).

Code final

Cliquez ici pour télécharger le code final

  • Cours
  • Tutoriels
  • Aide
  • À Propos