2 points par GN⁺ 2024-08-17 | 1 commentaires | Partager sur WhatsApp
  • CSS Grid est largement pris en charge par les principaux navigateurs depuis mars 2017, mais grid-template-areas reste encore sous-utilisé, alors qu’il permet de représenter visuellement une mise en page directement dans le CSS sans avoir à calculer les numéros de ligne
  • grid-template-areas fonctionne en plaçant des noms de zone dans des chaînes de caractères, puis en reliant les éléments enfants via grid-area ; un même nom doit obligatoirement former une zone rectangulaire
  • Les lignes de grille nommées consistent à attribuer des noms aux lignes, comme content-start / content-end, et le motif *-start / *-end peut être exploité par le navigateur comme une zone implicite
  • Pour des cartes inversées, des en-têtes responsives, des mises en page éditoriales, des publications de style Threads, des cartes superposées ou des mises en page conditionnelles avec :has(), on peut gérer des variantes de placement simplement en changeant les chaînes de zones du parent
  • Chrome, Safari et Firefox proposent tous des DevTools pour les zones Grid, et Firefox est particulièrement utile grâce à l’affichage des noms de zones et à l’autocomplétion des noms de ligne possibles lors de l’édition de grid-area

Rendre une mise en page plus lisible avec grid-template-areas

  • Les mises en page CSS Grid classiques utilisent souvent des déclarations explicites de numéros de ligne, comme grid-column: 1 / 3
  • Les numéros de ligne ne sont pas visibles avant inspection dans les DevTools, et dans une mise en page avec lignes et colonnes, il est difficile de calculer mentalement les bons numéros
  • Avec grid-template-areas, chaque cellule reçoit un nom, ce qui fait apparaître le CSS lui-même comme une carte de la mise en page
.page {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "item1 item2";
  gap: 1rem;
}

.item-1 {
  grid-area: item1;
}

.item-2 {
  grid-area: item2;
}
  • Les éléments enfants sont associés aux zones nommées via grid-area
  • Dans l’exemple de carte, une définition comme "featured featured article" permet à la zone featured d’occuper 2 colonnes et à la zone article d’en occuper 1

Syntaxe et règles à respecter absolument

  • grid-template-areas accepte une ou plusieurs chaînes de zones
    • Une seule chaîne crée une mise en page unidimensionnelle avec uniquement des colonnes
    • Plusieurs chaînes composent une mise en page multidimensionnelle avec lignes et colonnes
  • Lorsqu’on utilise plusieurs chaînes, les écrire sur plusieurs lignes rend la mise en page plus facile à lire
.element {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "aside main"
    "footer footer";
}
  • Chaque chaîne représente une ligne de la grille, qu’on peut envisager comme un tableau
  • Les zones définies avec le même nom doivent former un rectangle dans le code
/* invalid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "header footer";
}

/* valid */
.layout {
  grid-template-areas:
    "header header"
    "sidebar main"
    "sidebar footer";
}
  • Toutes les lignes doivent contenir le même nombre de jetons de zone, et même si une zone n’est pas utilisée, la cellule elle-même doit être définie
  • Les cellules vides peuvent être représentées par un point ou plusieurs points
.element {
  grid-template-areas:
    "aside main"
    "... footer";
}
  • Le point est le null cell token de la spécification CSS Grid, qui représente une cellule de grille vide

Relation entre lignes de grille nommées et zones

  • En CSS Grid, il y a toujours une ligne de plus que le nombre de colonnes
    • Avec 3 colonnes, on obtient 4 lignes de grille
  • Les lignes de grille nommées permettent d’attribuer un nom unique à une ligne au lieu d’utiliser uniquement des numéros
.layout {
  grid-template-columns:
    [full-start] 1fr
    [content-start] 2fr
    [content-end] 1fr [full-end];
}

.item {
  grid-column: content-start / content-end;
}
  • Nommer les lignes n’empêche pas de continuer à utiliser les lignes numérotées
  • La taille de piste (track size) correspond à la taille d’une colonne ou d’une ligne ; des valeurs comme 1fr 1fr sont des tailles de piste
  • Avec les lignes nommées, on nomme les lignes autour des pistes
.layout {
  display: grid;
  grid-template-columns:
    [aside-start] 200px [aside-end main-start] 1fr [main-end];
}
  • Une même ligne peut porter plusieurs noms ; dans l’exemple ci-dessus, aside-end et main-start désignent la même ligne
  • Si l’on définit des noms comme aside-start et aside-end, le navigateur peut autoriser un usage comme grid-column: aside via des noms de ligne implicites
  • Il n’est pas nécessaire de nommer toutes les lignes ; on peut ne nommer que les plus importantes
  • Lors du placement, on peut mélanger numéros et noms, par exemple grid-column: 1 / content-end

Gérer les variantes de placement avec les chaînes de zones du parent

  • Avec grid-template-areas, on peut modifier toute la mise en page en ne changeant que les chaînes de zones du parent, tout en conservant les mêmes noms grid-area sur les éléments enfants
.aside {
  grid-area: aside;
}

.main {
  grid-area: main;
}

.footer {
  grid-area: footer;
}
  • En gardant les mêmes noms aside, main et footer, il suffit de changer les chaînes grid-template-areas pour que toute la disposition soit mise à jour automatiquement
  • Le contrôle de la mise en page est centralisé dans la définition des zones du parent, ce qui facilite les ajustements

Inverser l’orientation d’une carte

  • Avec Flexbox, il est facile d’inverser l’orientation d’une carte via flex-direction: row-reverse
  • Avec CSS Grid et des numéros de ligne, changer le sens oblige à modifier à la fois la définition des colonnes et les valeurs grid-column de chaque enfant
  • Avec des zones nommées, il suffit d’attribuer des zones à l’image et au contenu de la carte, puis de changer l’ordre des zones dans le parent
.card {
  display: grid;
  grid-template-columns: 150px 1fr;
  grid-template-areas: "thumb content";
}

.card__thumb {
  grid-area: thumb;
}

.card__content {
  grid-area: content;
}

.card--flip {
  grid-template-columns: 1fr 150px;
  grid-template-areas: "content thumb";
}
  • La même disposition peut aussi être exprimée avec la propriété raccourcie grid-template
.card--flip {
  grid-template: "content image" / 1fr 150px;
}
  • La propriété raccourcie reste facultative, et certains préfèrent la version longue, jugée plus lisible

Mise en page d’en-tête responsive

  • Un en-tête avec un logo, une navigation et une zone d’actions peut au départ être composé de 3 colonnes de taille identique
  • Avec des numéros de ligne, il faut définir grid-column séparément pour .logo, .nav et .actions
  • Avec des noms de zone, on associe chaque enfant à logo, nav et actions, puis on ne change que grid-template-areas du parent selon le viewport
.header {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "logo nav actions";
}

.logo {
  grid-area: logo;
}

.nav {
  grid-area: nav;
}

.actions {
  grid-area: actions;
}
  • Sur de petites largeurs, on peut placer le logo et les actions sur la première ligne, puis la navigation sur toute la largeur
.header {
  grid-template-areas:
    "logo logo actions"
    "nav nav nav";
}
  • À partir de 380px, on peut placer le logo à gauche et la navigation avec les actions à droite
@media (min-width: 380px) {
  .header {
    grid-template-areas:
      "logo nav nav"
      "logo actions actions";
  }

  .nav {
    justify-self: end;
  }
}
  • À partir de 900px, on peut revenir à une disposition sur une seule ligne
@media (min-width: 900px) {
  .header {
    grid-template-areas: "logo nav actions";
  }
}
  • Les chaînes de zones agissent comme un mapping qui montre directement l’agencement de l’interface dans le CSS

Exemple de mise en page éditoriale

  • Une section contenant un titre, du texte et une image peut facilement adapter sa disposition selon la taille du viewport avec grid-template-areas
.section {
  display: grid;
  grid-template-areas:
    ". title title"
    "thumb content content";
  gap: 1rem;
}
  • Le point à gauche du titre représente un espace vide, c’est le null cell token
  • Dans un exemple de section inspiré du style de time.com, on utilise les zones feature, secondary et most-read ainsi que des colonnes vides de chaque côté
.featured-section {
  display: grid;
  grid-template-areas:
    ". feature most-read ."
    ". secondary most-read .";
  grid-template-columns: 1fr minmax(auto, 57.313rem) minmax(12rem, 18.75rem) 1fr;
  grid-template-rows: minmax(auto, 25rem) 1fr;
}
  • Les colonnes vides de chaque côté servent surtout de marges gauche et droite
  • Dans la version responsive, feature, secondary et most-read sont empilés verticalement sur petit écran, puis les colonnes et les zones sont redéfinies à partir de 500px et 900px
  • grid-template-rows peut être remplacé par la définition des zones et n’est donc pas indispensable

Composant de publication de style Threads

  • En examinant le CSS de Threads app by Meta, on peut voir un cas d’usage de CSS Grid pour un composant de publication
  • Dans l’exemple d’origine, les éléments sont placés avec grid-template-columns, grid-template-rows et des numéros de ligne
.postBody {
  grid-column-start: 2;
  grid-row-start: 2;
  grid-row-end: span 3;
}
  • Plusieurs variantes de publication peuvent être exprimées plus simplement avec grid-template-areas
.post {
  grid-template-areas:
    "avatar header"
    "avatar body"
    ". body"
    ". footer";
}

.post--reply {
  grid-template-rows: 40px max-content max-content;
  grid-template-areas:
    "avatar header"
    "body body"
    "body body"
    "footer footer";
}

.post--nested {
  grid-template-areas:
    "avatar header"
    "avatar body"
    "line body"
    "footer footer";
}
  • Il suffit de regarder les chaînes de zones pour distinguer les variantes par défaut, réponse et publication imbriquée

Éléments superposés et noms de zone

  • Dans grid-template-areas, un même nom doit former un rectangle ; répéter le même nom dans une forme non rectangulaire rend la déclaration invalide
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr fr;
  grid-template-areas:
    "card tag tag"
    "title title card";
}
  • Dans cet exemple, card ne forme pas un rectangle et la déclaration est donc invalid
  • Pour des cartes superposées, on peut définir de nouveaux noms de zone comme thumb-1 et thumb-2, puis les utiliser dans grid-column et grid-row
.card {
  display: grid;
  grid-template-columns: auto auto 1fr;
  grid-template-rows: auto auto;
  grid-template-areas:
    "thumb-1 tag"
    "title thumb-2";
}

.thumb {
  grid-column: thumb-1 / thumb-2;
  grid-row: thumb-1 / thumb-2;
}
  • Le tag et le titre peuvent chacun être placés avec grid-area, puis alignés avec align-self et justify-self
  • Si nécessaire, il faut aussi gérer l’ordre d’empilement des enfants, mais dans l’exemple, l’ordre source suffit
  • Cet exemple de superposition est inspiré de la page Oddbird’s Cascading Layouts

:has() et mise en page conditionnelle

  • En combinant le sélecteur CSS :has() et les zones Grid, on peut changer la mise en page selon la présence ou l’absence de certains éléments
  • On peut appliquer des définitions de zones différentes selon qu’un <figure> contient ou non un figcaption
figure {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-areas: "img img img";
  gap: 0.5rem;
}

img {
  grid-area: img;
}

figcaption {
  grid-area: caption;
}

.card:has(figcaption) {
  grid-template-areas:
    "img img caption"
    "img img .";
}

Prise en charge des directions multilingues LTR/RTL

  • CSS Grid ajuste la mise en page selon que la page est en LTR ou en RTL
  • Les zones de grille nommées suivent elles aussi la direction de la page ; la mise en page s’inverse donc en configuration RTL
  • Pour aller plus loin sur la création de mises en page RTL, on peut consulter le guide RTL Styling 101

Différences de prise en charge dans les DevTools

  • Chrome, Safari et Firefox proposent tous des DevTools pour les zones Grid
  • Chrome
    • Place les noms de zone en haut à gauche, ce qui peut les faire se chevaucher visuellement
    • L’overlay coloré peut modifier la façon dont le design apparaît
  • Safari
    • Le contour rose aide à distinguer clairement les éléments
    • Permet de voir les noms de ligne
    • L’affichage des noms de ligne pourrait encore être amélioré, notamment dans la manière dont ils s’empilent
  • Firefox
    • Affiche les noms de zone plus clairement que Chrome et Safari
    • Propose une liste d’autocomplétion lors de la saisie de noms personnalisés comme *-start et *-end
    • Fournit la liste de tous les noms de ligne possibles lors de l’édition de grid-area sur un élément enfant

Ressources de référence

1 commentaires

 
GN⁺ 2024-08-17
Avis sur Hacker News
  • La démo animée était assez intéressante, mais déception en découvrant que cette animation n’était pas faite en CSS
    Après avoir appris Flexbox, je me suis dit que « ça suffisait », et je n’ai pas approfondi Grid. Il semble y avoir des raisons de préférer Grid [0], mais globalement je n’ai jamais eu besoin de faire quelque chose qui ne soit possible qu’avec Grid, et pour les tableaux de données j’utilise de vrais <table>
    [0] https://css-tricks.com/css-grid-replace-flexbox/

    • C’est une bonne chose d’avoir appris un outil qui couvre tous tes besoins
      Je n’ai utilisé Grid que pour des galeries d’images responsives comme https://labs.jensimmons.com/2016/examples/image-gallery-grid... ou des cartes responsives comme https://every-layout.dev/demos/grid-cards/. grid-template-columns vaut la peine d’être appris, et grid-gap est pratique. Pour le reste, j’ai l’impression que Flexbox gère presque tout
      En revanche, grid-template-areas reste encore un peu flou pour moi. L’article avance que c’est plus simple pour ajuster la mise en page selon les breakpoints ou quand « un membre de l’équipe doit modifier la mise en page », mais je ne suis peut-être tout simplement pas le public visé
    • Un outil amusant pour apprendre Grid : https://cssgridgarden.com/
    • Flex suffit dans la plupart des cas, mais Grid a aussi sa place. Par exemple pour une mise en page de cartes en 3 colonnes qui se réduit à une carte par ligne sur petit écran, une structure de page avec une sidebar dédiée, ou des éléments dont certaines positions doivent être conservées pendant le redimensionnement
      On peut utiliser les deux selon les besoins, et combinés, ils deviennent un outil de mise en page très puissant
    • « Non, Flexbox n’est pas “assez bien” »
      https://www.youtube.com/watch?v=MWWcZzossc8
  • Attends, 1/3 n’est pas une fraction mais une plage de 1 à 3 ? Je ne comprends pas pourquoi ils ont choisi cette syntaxe. Il existe en programmation beaucoup de syntaxes raisonnables et bien connues pour représenter des plages, par exemple 1..3

    • La première chose à savoir sur CSS, c’est que CSS n’est pas l’expression d’un langage de programmation, mais emploie le langage de la mise en page imprimée
      Il me semble qu’une bonne partie des problèmes que les programmeurs rencontrent avec CSS vient de ce malentendu
    • Les fonctionnalités de Grid sont bonnes, mais la syntaxe est assez différente du reste de CSS, donc elle prête à confusion. On dirait que ce coin-là a été conçu à part, ou qu’il porte les traces d’une approche du type « cette fois, faisons les choses correctement »
    • De part et d’autre de la barre oblique, il n’y a pas forcément que des nombres ; il peut aussi y avoir plusieurs mots : https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
    • Imagine qu’on explique à un programmeur qu’en CSS, !important ne veut pas dire « pas important », mais « important ! »
  • Je n’ai jamais vraiment maîtrisé ni Grid ni Flexbox. La dernière stratégie de mise en page que je maniais à peu près correctement était float. Cet article m’a donné la confiance nécessaire pour essayer CSS Grid dans ma prochaine mise en page, et il est aussi très bien fait

    • Si tu as déjà utilisé float, Grid et Flex seront beaucoup plus faciles. Il suffit d’y consacrer un jour ou deux et de créer quelques mises en page. Contrairement à l’époque où il fallait se battre avec les anciens navigateurs, ces deux-là fonctionnent tout simplement bien, au point que c’en est presque ennuyeux
      Il existe beaucoup de bons articles, mais ces deux articles de CSS-Tricks m’ont suffi
      https://css-tricks.com/snippets/css/a-guide-to-flexbox/
      https://css-tricks.com/snippets/css/complete-guide-grid/
    • On peut tenir un certain temps sans apprendre Grid, mais Flexbox est quasiment indispensable. C’est beaucoup plus pratique que les anciens hacks à base de float, et c’est présent partout dans le CSS moderne
      En plus des articles CSS-Tricks déjà cités, je recommande le guide Flexbox de MDN [1] et la référence « CSS flexible box layout » [2]. Ils m’ont aidé à comprendre plus en profondeur les concepts derrière Flexbox, ses propriétés et le fonctionnement réel des propriétés raccourcies
      [1]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layou...
      [2]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexibl...
    • Flexbox ressemble à une version bien conçue des systèmes de grille basés sur float. On peut disposer les éléments enfants verticalement ou horizontalement, alors qu’avec float et les hacks clearfix, on était en pratique limité à une disposition par lignes
      Cela dit, Flexbox reste proche d’une mise en page unidimensionnelle pouvant passer à la ligne, donc l’astuce consiste à imbriquer et empiler. Grid, avec ses templates et ses enfants directs qui occupent des zones prédéfinies, est plus statique que Flexbox, et il a pour limite de ne pas affecter les éléments imbriqués à l’intérieur. Mais subgrid semble devoir changer cela
    • Si tu comprends float, c’est déjà un accomplissement rare ; Flex/Grid devraient donc être assez agréables à utiliser
    • Grid a beaucoup de fonctionnalités, mais Flex est suffisamment simple tout en restant très puissant
  • Ressources associées :
    Grid Garden https://cssgridgarden.com
    Flexbox Froggy https://flexboxfroggy.com

  • J’aimerais qu’il existe une version encore plus basique que ce document, une sorte d’« avant l’introduction ». Je suis resté bloqué dès la partie d’introduction et je n’ai pas réussi à avancer. En particulier, dans le passage « pour placer les éléments enfants dans une Grid, il faut indiquer le numéro de ligne de chaque élément avec grid-column », je ne comprenais pas ce que signifiait numéro de ligne ici
    J’ai essayé de continuer en me disant que je comprendrais avec le contexte, mais je me suis retrouvé bloqué aussitôt sur des expressions comme 1 / 3 ou 1 / 4

    • Les numéros de ligne sont les lignes qui séparent les colonnes. S’il y a 2 colonnes, il y a 3 lignes : dans |a||b|, les deux lignes du milieu comptent en réalité comme une seule, donc il y en a 3 au total
      Ainsi, 1/3 n’est pas une fraction mais une plage de colonnes, et signifie « commence à la ligne 1 et se termine à la ligne 3 »
    • Si on fait défiler un peu plus bas, il y a une démo live qu’on peut manipuler directement pour voir ce qui se passe
      Le nom « numéro de ligne » n’est pas très heureux, mais en pratique il s’agit des bords des colonnes. Donc 1/3 va du bord n° 1, c’est-à-dire tout à gauche, jusqu’au bord n° 3, et occupe les 2 colonnes entières
  • Pour CSS Grid, je recommande vivement Jen Simmons Mondrian with auto flow. Il suffit d’aller sur https://labs.jensimmons.com/2017/01-011.html, d’appuyer sur C et D, puis de redimensionner la fenêtre. Il y a aussi une vidéo YouTube à regarder avec : https://www.youtube.com/watch?v=qNtJ5p3h2A4
    C’est vraiment superbe
    Ce que j’aimerais encore comprendre avec auto flow, c’est comment détecter et remplir les espaces vides. Quand on a des objets de tailles variées disposés aléatoirement, comment faire pour qu’auto flow ne laisse pas de trous ? Ou bien peut-on détecter les trous et y ajouter quelque chose ?

  • J’espère que la question n’est pas idiote, mais pourquoi la syntaxe a-t-elle été définie avec une barre oblique, comme 1/2 ou 3/4 ? Quelque chose comme 1-2, de la colonne 1 à la colonne 2, ou 1->2, ne serait-il pas plus naturel ?

    • Les numéros de colonne peuvent être négatifs. Dans ce cas, lequel serait préférable : 1--1, 1->-1 ou 1/-1 ?
    • La flèche serait peut-être possible, mais il y a une raison à la présence d’espaces de part et d’autre. Il n’y a pas que des nombres qui peuvent apparaître : https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column...
      En CSS, les valeurs sont déjà séparées par des espaces, et si l’on tient compte aussi de l’intuition qu’on associe généralement aux tirets, les formes ci-dessous sont nettement préférables
      grid-column: 4 somegridarea / 6;
      grid-column: span 3 / 6;
      grid-column: span somegridarea / span someothergridarea;
      C’est beaucoup plus clair que d’écrire ceci
      grid-column: 4 somegridarea-6;
      grid-column: span 3-6;
      grid-column: span 3->6;
      grid-column: span somegridarea-span someothergridarea;
      grid-column: span somegridarea->span someothergridarea;
  • J’aime vraiment ce genre de billets de blog interactifs. Pour Grid, je recommande vivement de manipuler directement les grid areas dans un outil comme https://grid.layoutit.com/
    J’utilise ce site depuis des années pour planifier des mises en page Grid, et cela rend l’ajustement des espacements beaucoup plus facile

  • C’est peut-être la première fois que je comprends réellement CSS Grid. L’affichage des numéros aide énormément, et c’est un article auquel je reviendrai souvent

    • Les outils de développement de Firefox peuvent aussi afficher ces numéros par défaut. Pour Chrome, je ne suis pas sûr
  • J’aime CSS Grid et le concept de zones, mais je pense que la partie la plus difficile reste la gestion du responsive, surtout entre les tailles mobile et desktop. Selon quels éléments d’UI doivent être ouverts, ou s’ils doivent occuper tout l’écran, il faut souvent mettre à jour grid-template-area ainsi que la taille des lignes/colonnes en JavaScript
    Je n’ai pas encore trouvé de monde où minmax ou calc suffisent à résoudre ça, et j’aimerais que quelqu’un connaisse la réponse

    • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_contain...
    • Dans ce genre de cas, une bonne approche consiste à continuer d’utiliser Grid tel quel, mais à mettre les valeurs des lignes/colonnes dans des variables CSS comme var(--foo), plutôt que dans des valeurs fixes
      Ainsi, côté JavaScript, il suffit de mettre à jour la valeur de cette variable, et Grid la prend en compte
    • J’ai été surpris que l’article ne souligne pas davantage à quel point les zones de template sont utiles pour le responsive. Avec les media queries, on peut définir des zones Grid différentes selon l’écran, et déplacer chaque élément dans la disposition souhaitée pour cette taille d’écran. Si un élément doit être masqué à une certaine taille, il suffit de lui appliquer display: none à cette taille
      Exemple très simple : https://codepen.io/trescenzi/pen/vYqpjvL
    • Dans beaucoup de ces cas, j’ai l’impression que :has() ou subgrid pourraient résoudre le problème, mais je n’ai pas beaucoup d’expérience directe
    • Avez-vous essayé les media queries ?