Photo de Luca Bravo sur Unsplash

Construire une grille produits avec CSS Grid aujourd'hui

Sébastien (@sdussaut)

Aaah les grilles produits. Que le premier ou la première n’ayant jamais bataillé de toute sa carrière pour réaliser un affichage propre et flexible d’une grille produits en pourcentage me jette la première pierre.
Mais si, souvenez-vous du brief : une grille produits à largeur fluide et dont le nombre d’éléments s’adapte en fonction de la largeur, éléments qui d’ailleurs doivent (dans l’idéal) avoir une largeur minimale mais aussi maximale afin de conserver l’homogénéité de l’interface (et ne pas risquer l’ire de votre directeur•trice artistique). J’oubliais : la grille s’affiche en colonnes mais aussi… sur une colonne unique (pour afficher plus de détails sur le produit par exemple).

Ça c’était avant

Il y a quelques temps (disons entre 10 et 15 ans), pour répondre à cette problématique nous aurions fait un joli tableau HTML. Avantage : c’était flexible en largeur et presque toujours bien calé (hum). Inconvénients : le balisage un peu lourd, le nombre d’éléments par ligne figé et la construction de la dernière ligne loin d’être optimale à gérer lors de la phase de dynamisation (des amateurs de calcul de l’attribut rowspan dynamiquement en fonction du nombre de produits dans la grille ?). Et côté sémantique… on repassera.

Ensuite, pendant longtemps, il y a eu une période partagée entre l’utilisation des flottants et leurs classes utilitaires pour éviter un effet d’escalier disgracieux, et l’utilisation des inline-block avec des techniques (qui relevaient d’ailleurs plus du bricolage que de la science pure) à base de font-size: 0; pour faire disparaître les espacements naturels entre les éléments inline.
Je vais vous gâcher la surprise, mais j’étais de la première école. Devoir mettre à 0 une taille de texte pour positionner un bloc me paraissait (et me paraît toujours) contre nature. Pour moi, cela a toujours relevé du hack pur et simple (même si, avouons-le cela fonctionnait… tant qu’on ne voulait pas faire d’héritage sur la taille de police bien entendu). 

Et un beau jour un nouveau venu fait son entrée : flexbox. Et nous voici donc avec un outil qui nous permet enfin d’avoir des blocs qui agencent leur taille en fonction de leur contenu sans jamais dépasser leur conteneur, qui nous permet de redistribuer l’espace restant entre les blocs, de les réordonner sans toucher au DOM, de centrer le contenu verticalement… Et bien sûr il est tout à fait possible de s’en servir pour de la mise en page même s’il est plus adapté pour les petits éléments.

Et voilà qu’un récent ajout vient redistribuer toutes les cartes : CSS Grid. Et pour notre plus grand bonheur, il a clairement été pensé pour faire du layout.

Retour vers le futur

Nous voici donc de retour à aujourd’hui avec le support toujours meilleur de CSS Grid.
CSS Grid – vous en avez forcément déjà entendu parler étant donnée l’agitation que cela provoque depuis quelque temps déjà – est le dernier outil en date pour réaliser l’agencement de nos pages web.
CSS Grid a pour principe fondateur l’agencement d’éléments en fonction... d’une grille. Il est ainsi possible de déterminer avec précision les coordonnées exactes de nos éléments sur la grille – grille que nous aurons préalablement définie : nombre de colonnes, de lignes, hauteurs et largeurs, gouttières entre les cellules, etc ou encore de laisser la grille s'agencer automatiquement.
Dans cet article, nous nous attarderons sur l’utilisation de CSS Grid dans le cas qui nous occupe : la mise en place d’une grille de catalogue produits. Je laisse volontairement les détails concernant les bases de l’utilisation de Grid de côté, d’autres l’ayant déjà fait.

Mise en route

Précisons un point important tout de suite : oui, il est tout à fait possible d’utiliser Grid en production aujourd’hui. Cependant, et comme toujours, le périmètre navigateurs de votre projet va avoir un impact sur votre manière de l’implémenter et quelles solutions de substitution vous allez devoir mettre en place. On reviendra plus loin notamment sur le cas Internet Explorer/MS Edge qui, si on se fie à caniuse.com, supportent CSS Grid. On verra que la réalité est plus complexe que cela.

Revenons à nos moutons. Pour rappel, voici ce que nous essayons d’obtenir :

  • une grille produits ;
  • répartie sur plusieurs lignes et colonnes ;
  • composée d’un nombre non défini d’éléments par ligne ;
  • éléments qui doivent être fluides en largeur ;
  • et sans employer javascript bien entendu.

    Voici la structure HTML à partir de laquelle nous allons travailler :

    <ul class="product-grid">
      <li class="product-item">
        <a href="#">
          <img src="" alt="Product picture" />
          <p>
            <strong>Product name</strong>
            <span class="desc">Product description</span>
            <span class="price">1 248 €</span>
          </p>
        </a>
      </li></ul>
    
    Notre structure HTML

    Et quelques styles de base :

    .product-grid {
      list-style-type: none;
      margin: 15px;
      padding-left: 0;
    }
    
    .product-item a {
      color: #333;
      display: flex;
      text-decoration: none;
    }
    
    .product-item img {
      background-color: #c5cae9;
      border: 1px solid #7986cb;
      display: block;
      height: 150px;
      width: 150px;
    }
    
    .product-item p {
      display: flex;
      flex-direction: column;
      margin: 0;
      padding-left: 10px;
    }
    
    .product-item .price {
      border-bottom: 1px solid #ddd;
      margin-top: auto;
      padding-bottom: 5px;
      text-align: right;
    }
    
    Nos styles CSS

    Vous pouvez voir l’exemple sur cette page.

    Pas très engageant pour l’instant. Ajoutons donc un peu de CSS Grid par dessus tout ça et voyons ce que ça donne.

    /* grid styles */
    
    .product-grid {
      display: grid;
      grid-gap: 10px;
      grid-template-columns: 1fr;
      grid-template-rows: 150px;
    }
    
    Mise en place d'une grille simple

    Dans cet exemple, l’affichage en grille est activé à l’aide de la valeur grid de la propriété display. Cependant, pour fonctionner, Grid a besoin d’autres propriétés : il nous faut définir les colonnes (à l’aide de grid-template-columns) et les lignes (avec grid-template-rows).

    grid-template-columns accepte principalement des valeurs de dimension séparées par des espaces, chaque valeur définissant une colonne. Ainsi dans l’exemple ci-dessus, nous définissons une colonne unique prenant toute la largeur de la grille. L’unité fr a été introduite avec Grid afin de pouvoir exprimer des largeurs en fractions de la grille. Cette unité se comporte comme la valeur numérique de flex-grow. Ainsi, l’exemple suivant produira une grille de deux colonnes dont la seconde est deux fois plus large que la première :

    .product-grid {
      grid-template-columns: 1fr 2fr;
      …
    }
    
    Déclaration de deux colonnes avec l’unité de fraction

    La dernière propriété que nous ajoutons, grid-gap, permet de définir les gouttières entre les cellules de la grille. Il s’agit d’une propriété raccourcie, acceptant une valeur (pour les gouttières des lignes et des colonnes) ou deux sous cette forme grid-gap: <lignes> <colonnes>;.

    Agencement automatique des cellules

    Nous savons maintenant construire une grille avec un nombre défini de colonnes. Mais le brief initial incluait un ajustement automatique des colonnes et des lignes en fonction du nombre d’éléments les constituant.

    C’est là qu’entre en jeu l’algorithme d’agencement automatique de CSS Grid. C’est probablement un des outils de mise en page les plus puissants dont nous disposons à l’heure actuelle.

    Changeons un peu notre précédente déclaration :

    .product-grid {
      display: grid;
      grid-template-columns: repeat( 4, 300px);
      grid-template-rows: 150px;
      grid-gap: 10px;
    }
    
    Agencement de notre grille

    La fonction repeat() permet de répéter un certain nombre de fois un template de ligne ou de colonnes. Le premier paramètre représente le nombre de répétitions, le second le template de colonne ou de ligne. Dans l’exemple ci-dessus, on crée une grille de 4 colonnes de 300px de large chacune, l’espace restant n’étant pas (encore) redistribué.

    Afin de rendre cette création de colonnes plus souple et plus dynamique, CSS Grid nous apporte d’autres outils : auto-fill/auto-fit et minmax().
    auto-fill et auto-fit sont au cœur de l’agencement dynamique de la grille. En effet, en appliquant un de ces deux mots-clefs en lieu et place du nombre de répétitions, on indique au navigateur d’essayer de faire entrer un maximum de colonnes dans la largeur de la grille, rendant ainsi la grille complètement fluide et donc plus robuste.

    .product-grid {
      display: grid;
      grid-template-columns: repeat( auto-fit, 300px);
      grid-template-rows: 150px;
      grid-gap: 10px;
    }
    
    Rendre la grille fluide

    A ce stade, notre grille est fluide, le nombre d’éléments par ligne est également fluide. Il ne nous reste donc plus qu’à rendre les éléments eux-même fluides.
    C’est en utilisant la fonction minmax() que nous allons y parvenir. minmax() permet de poser des bornes pour la largeur de nos colonnes, tout en redistribuant l’espace restant entre toutes les colonnes équitablement (à la manière de flexbox). Ainsi l’expression suivante indiquera au navigateur que nos colonnes doivent être comprises entre 200 et 350px de large, espace supplémentaire redistribué compris :

    minmax( 200px, 350px)
    
    Exemple de déclaration de minmax()

    Notre code mis à jour devient donc :

    .product-grid {
      display: grid;
      grid-template-columns: repeat( auto-fit, minmax( 300px, 1fr));
      grid-template-rows: 150px;
      grid-gap: 10px;
    }
    
    Rendre les colonnes fluides également

    Un dernier ajout a fait son apparition : 1fr pour la borne supérieure de la taille de nos colonnes. Cela nous permet d’avoir des colonnes qui font au minimum 300px de large mais qu’aucune ne soit plus grande que les autres.

    Gestion de l’amélioration progressive

    Nous voici pratiquement à la fin de notre exercice. Il ne reste plus qu’à s’occuper des navigateurs ne supportant pas CSS Grid ou supportant une ancienne version de la spécification.

    J’en parlais plus haut, Internet Explorer et les premières versions de MS Edge (< 16) supportent CSS Grid (en fait c’est même Microsoft qui a publié la première proposition pour Grid). Mais ils supportent l’ancienne version de la spécification. Il va donc falloir s’en accommoder.

    Avant de passer à la partie technique, quelques précisions sur le support de Grid dans IE 10, 11 et MS Edge < 16 s’imposent. Comme l’écrivait Rachel Andrew dès 2016, il existe diverses incompatibilités entre la version de CSS Grid implémentée dans ces navigateurs et celle de la spécification plus récente :

    • pas de support pour les gouttières : il faudra les simuler par des colonnes/lignes vides ;
    • pas d’agencement automatique ;
    • certaines propriétés portent le même nom mais ne se comportent pas de la même façon, rendant plus complexe une éventuelle amélioration progressive.

      Je vous laisse consulter l’article de Rachel Andrew pour plus de détails sur ces incompatibilités mais s’il y a une chose à retenir c’est la suivante : un usage basique de CSS Grid fonctionnera dans ces navigateurs. Au delà, il faudra inclure cette famille de navigateurs dans votre solution de fallback.

      La mise en place de l’amélioration progressive pour CSS Grid est plutôt simple à gérer grâce à l’emploi de @supports. Le support d’Internet Explorer et de MS Edge < 16 étant préfixé il est ainsi aisé de les exclure des propriétés avancées de Grid :

      /* Grille pour tous les navigateurs, avec des float par exemple */
      
      .product-grid {
        …
      }
      
      /* Propriétés CSS Grid pour les navigateurs avancés */
      
      @supports (display: grid) {
        .product-grid {
          display: grid;
          grid-template-columns: repeat( auto-fit, minmax( 300px, 1fr));
          grid-template-rows: 150px;
          grid-gap: 10px;
        }
      }
      
      Ajout de l'amélioration progressive

      Et voilà ! Nous avons notre grille produits avec CSS Grid et amélioration progressive sans JavaScript. 

      La suite

      Comme on a pu le voir, CSS Grid est un outil vraiment performant pour la mise en page. Nous n’avons cependant fait qu’effleurer la surface de ce dont il est capable : il est par exemple possible de nommer des zones et d’y affecter des éléments directement, d’ajuster la largeur des colonnes en fonction de leur contenu, etc.
      CSS évolue. A nous de nous approprier ces nouveaux outils et d’en exploiter tout le potentiel !

      Aller plus loin

      Si CSS Grid vous intrigue, je vous conseille de suivre Rachel Andrew et Jen Simmons qui aujourd’hui sont les références en la matière. Quelques autres liens :