Comment créer des tableaux réactifs avec du CSS pur à l'aide du module Grid Layout

TL; DR

Le moyen le plus courant d'afficher une collection de données similaires est d'utiliser des tableaux, mais les tableaux HTML ont l'inconvénient d'être difficiles à rendre réactifs.

Dans cet article, j'utilise le module CSS Grid Layout et les propriétés CSS (et pas de Javascript) pour mettre en page des tableaux qui enveloppent les colonnes en fonction de la largeur de l'écran, ce qui change davantage en une carte basée sur la disposition des petits écrans.

Pour les impatients, regardez le stylo suivant pour une implémentation prototypique.

Un peu d'histoire des tableaux HTML réactifs

Les tables réactives ne sont pas un nouveau sujet et de nombreuses solutions ont déjà été proposées. «Responsive Table Data Roundup», publié pour la première fois en 2012 par Chris Coyier, résume très bien les choses (y compris une mise à jour de 2018).

«Tableaux vraiment réactifs utilisant CSS3 Flexbox» de Vasan Subramanian montre une idée de wrapping de colonnes, implémentée avec Flexbox.

Même si de nombreuses idées intéressantes ont été proposées, des bibliothèques comme bootstrap optent pour le défilement horizontal pour les petits écrans.

Comme nous avons maintenant CSS Grid, je pense que nous pourrions avoir une meilleure alternative commune au défilement horizontal.

Tableaux HTML

En commençant par les bases, un tableau en HTML est un format de mise en page permettant d'afficher des collections d'éléments à travers une matrice de lignes et de colonnes. Les éléments sont disposés en lignes, avec les mêmes attributs de données dans les mêmes colonnes, les lignes étant souvent triées avec un ou plusieurs attributs triables. Le format vous offre une vue à vol d'oiseau pour saisir et examiner rapidement de grandes quantités de données.

Par exemple, voici un tableau hypothétique des détails des bons de commande, que vous pouvez voir dans une application d'achat.

Un article, dans ce cas, est un détail de commande d'achat, qui a des attributs tels que le numéro de pièce, la description de la pièce, etc.

Lors de l'utilisation de tableaux HTML, la mise en page des données est codée en dur sous forme de lignes et de colonnes (par exemple et ). Cela peut être suffisant pour une utilisation par un écran qui s'adapte à toute la largeur de la table, mais en réalité, cela ne s'applique pas à la myriade d'appareils qui existent aujourd'hui. En termes de hacks, vous pouvez modifier la propriété d'affichage des tableaux et utiliser n'importe quelle mise en page que vous pouvez faire avec CSS en général, mais cela ne semble pas sémantiquement correct.

Tables redéfinies (= Collection d'éléments)

Commençons par redéfinir la manière dont les données de table doivent être exprimées en HTML.

Comme indiqué précédemment, puisque les données de table sont essentiellement une collection ordonnée d'éléments, il semble naturel d'utiliser des listes ordonnées. De plus, comme les tableaux sont souvent utilisés pour compléter les descriptions textuelles, il semble naturel de les inclure dans une section, mais cela dépendra du contexte dans lequel les données du tableau sont utilisées.

  1. # Part Number Part Description ...
  2. 1 100-10001 Description of part ...
  3. ...

Les Vanilla sont utilisés pour exprimer les attributs des éléments puisque HTML5 ne définit pas de balise appropriée pour cela. La clé ici est d'exprimer des attributs sémantiquement similaires sous la forme d'une hiérarchie de 's. Cette structure sera utilisée lors de la définition de la présentation des données. J'y reviendrai dans la section suivante sur le thème du style.

En ce qui concerne les données réelles à l'intérieur de l' élément, le premier élément de la liste est l'en-tête et le reste des éléments sont les données réelles.

Maintenant, il est temps de commencer à parler de styliser les éléments avec CSS Grid.

Collections d'articles de style

L'idée de base ici est d'afficher tous les attributs de l'élément sous forme de tableau normal, si la largeur d'affichage le permet. Cette disposition a le luxe de pouvoir voir autant d'éléments (lignes) que possible.

Lorsque la largeur de l'affichage devient plus étroite, certains attributs sont empilés verticalement, afin de gagner de l'espace horizontal. Le choix des attributs d'empilement doit être basé sur:

  1. Les attributs ont-ils un sens lorsqu'ils sont empilés verticalement? et,
  2. Lorsqu'il est empilé verticalement, économise-t-il de l'espace horizontal?

Lorsque la largeur se réduit davantage à la taille d'un appareil mobile, chaque élément est affiché sous forme de carte. Cette mise en page est redondante car les noms d'attributs sont affichés à plusieurs reprises sur chaque carte, et ont le moins de visibilité possible, mais ne compromet pas la convivialité (par exemple, défilement horizontal, texte super petit, etc.).

Passons maintenant aux détails.

Styling Étape 1: Tableau complet

Voici un résumé visuel de la façon dont les choses seront implémentées avec CSS Grid.

Afin de rendre les colonnes enveloppantes, plusieurs conteneurs de grille sont définis comme une hiérarchie. La boîte rouge est un conteneur de grille pour chaque ligne, et la boîte bleue est un conteneur pour chaque groupe de colonnes qui encapsule.

Commençons par définir la liste comme un conteneur de grille en définissant une classe appelée .item-containeret en l'appliquant au

  • (la boîte rouge).

    .item-container { display: grid; grid-template-columns: 2em 2em 10fr 2fr 2fr 2fr 2fr 5em 5em; }

    Le nombre de colonnes explicites spécifié par grid-template-columnsest neuf, ce qui correspond au nombre de colonnes de niveau supérieur , directement sous

  • .

    La largeur de la colonne est définie en longueur relative pour que les colonnes s'enroulent. La fraction réelle doit être affinée en fonction du contenu.

    Les colonnes qui ne sont pas enveloppées sont définies en longueur absolue pour maximiser l'utilisation de la largeur pour les colonnes d'habillage. Dans l'exemple des détails du bon de commande, la deuxième colonne est un identifiant à deux chiffres, j'ai donc défini la largeur pour doubler cette taille de 2 m.

    Ensuite, nous définissons un autre conteneur de grille appelé .attribute-containeret l'appliquons sur tous les intermédiaires sous la liste (la boîte bleue).

    .attribute-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--column-width-min), 1fr)); }

    The minimum column width for all grid items under .attribute-container is specified with a CSS variable called --column-width-min(more on this later) using the minmax function, with the maximum set to take the rest of the space (e.g. one fraction). Since grid-template-columns are repeated, available horizontal space will be split into the maximum number of columns that could take at least --column-width-min, and the rest of the columns would go to the next line. The column’s width will be stretched if there is excess horizontal space because the repeat is auto-fited.

    Styling Step 2: Wrapping Table

    Next, --column-width-min needs to be specified independently for each column in order to wrap. Just to be clear, the variables need to be specified in order for the full table to render properly as well. To do this, a class is set for each .attribute-container, and a different --column-width-min is specified for each class scope.

    Let’s take a look at the HTML where .part-id is applied,

     Part Number Part Description 

    and the CSS:

    .part-id { --column-width-min: 10em; }

    This specific grid container will have two columns, as long as the available width is wider than 10em for each grid item (e.g. the grid container is wider than 20em). Once the grid container’s width becomes narrower than 20em, the second grid item will go to the next row.

    When we combine CSS properties like this, we need only one grid container .attribute-container, with the details changing where the class is applied.

    We can further nest .attribute-containers, to have multiple levels of wrapping with different widths, as in the following exert.

     Part Number Part Description Vendor Number Vendor Name .part-information { --column-width-min: 10em; } .part-id { --column-width-min: 10em; } .vendor-information { --column-width-min: 8em; }

    All of the above is enclosed in the following media query. The actual breakpoint should be selected based on the width necessary when your table is wrapped to the extreme.

    @media screen and (min-width: 737px) { ... }

    Styling Step Three: Card Layout

    The card layout will look like a typical form with attribute names in the first column and attribute values in the second column.

    To do this, a class called .attribute is defined and applied to all leaf tags under the

  • Original text


  • .

    .attribute { display: grid; grid-template-columns: minmax(9em, 30%) 1fr; }

    The attribute names are taken from a custom attribute of the leaf   called data-name, for example , and a pseudo-element is created. The pseudo-element will be subject to the grid container’s layout.

    .attribute::before { content: attr(data-name); }

    The first item in the list is the header and does not need to be displayed.

    /* Don't display the first item, since it is used to display the header for tabular layouts*/ .collection-container>li:first-child { display: none; }

    And finally, the cards are laid out in one column for mobile devices, but two for screens with a little bit more width, but not enough for displaying a table.

    /* 2 Column Card Layout */ @media screen and (max-width: 736px) { .collection-container { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 20px; } ... } /* 1 Column Card Layout */ @media screen and (max-width:580px) { .collection-container { display: grid; grid-template-columns: 1fr; } }

    Finishing Notes

    Accessibility is an area that wasn’t considered at all and may have some space for improvement.

    If you have any ideas or second thoughts, please feel free to comment!

    And of course, thanks for reading.