Mise en page du magazine Responsive Grid en seulement 20 lignes de CSS

Online Coding Courses for Kids

Je travaillais récemment sur une version moderne du blogroll. L’idée était de proposer aux lecteurs une sélection des derniers articles de ces blogs dans une présentation de style magazine, au lieu de simplement afficher une liste de nos blogs préférés dans la barre latérale.

La partie facile consistait à récupérer une liste de messages avec des extraits de nos flux RSS préférés. Pour cela, nous avons utilisé un plugin WordPress, Feedzy lite, qui peut regrouper plusieurs flux dans une seule liste ordonnée dans le temps – parfait pour présenter leurs dernières offres. La partie difficile a été de rendre tout cela génial.

L’interface utilisateur de la liste par défaut du plugin est plutôt fade, donc je voulais le styliser pour ressembler à un site Web de journal ou de magazine avec un mélange de panneaux de «contenu vedette» plus petits et plus grands.

Cela semble être un cas idéal pour CSS Grid! Créez une disposition de grille pour différentes mises en page, disons une mise en page à cinq colonnes et une mise en page à trois colonnes, puis utilisez des requêtes multimédias pour basculer entre elles à différents points d’arrêt. Droite? Mais avons-nous réellement besoin de ces requêtes multimédias – et de tous les tracas d’identification des points de rupture – lorsque nous pouvons utiliser la grille auto-fit des options pour créer automatiquement une grille réactive fluide pour nous?

L’approche semblait tentante, mais quand j’ai commencé à introduire des éléments couvrant des colonnes, j’ai eu des problèmes avec la grille qui débordait sur des écrans étroits. Les requêtes des médias semblaient être la seule solution. Autrement dit, jusqu’à ce que je trouve une solution de contournement!

Après avoir regardé plusieurs tutoriels sur CSS Grid, j’ai trouvé qu’ils se répartissaient largement en deux camps:

  1. Tutoriels qui vous montrent comment créer une mise en page intéressante avec des éléments fractionnés, mais pour un nombre fixe de colonnes.
  2. Tutoriels qui expliquent comment créer une grille réactive qui se redimensionne automatiquement, mais avec tous les éléments de la grille de la même largeur (c’est-à-dire sans colonnes réparties).

Je veux que la grille fasse les deux: créer une mise en page fluide entièrement réactive qui comprend également un redimensionnement réactif des éléments multi-colonnes.

La beauté est qu’une fois que vous comprenez les limites des grilles réactives, et pourquoi et quand les étendues de colonne interrompent la réactivité de la grille, il est possible de définir une mise en page de style magazine / actualités réactive une douzaine de lignes de code plus une simple requête média (ou même sans requête média si vous êtes prêt à limiter vos options de durée).

Voici un visuel montrant le plugin RSS dès la sortie de la boîte et à quoi il ressemblera après l’avoir stylisé.

(Démo)

Cette disposition de grille de style magazine est entièrement réactive avec les panneaux en vedette colorés s’ajustant dynamiquement lorsque le nombre de colonnes change. La page affiche environ 50 publications, mais le code de mise en page est indépendant du nombre d’éléments affichés. Augmentez le plugin pour afficher 100 éléments et la mise en page reste intéressante tout le long.

Tout cela est réalisé en utilisant uniquement CSS et avec une seule requête multimédia pour gérer un affichage sur une seule colonne sur les écrans les plus étroits (c’est-à-dire plus petits que 460 pixels).

Incroyablement, cette mise en page n’a pris que 21 lignes de CSS (hors style de contenu global). Cependant, pour obtenir une telle flexibilité dans quelques lignes de code, j’ai dû creuser profondément dans les parties les plus obscures de certaines de CSS Grid et apprendre à contourner certaines de ses limitations inhérentes.

Les éléments essentiels du code qui produisent cette mise en page sont incroyablement courts et témoignent de l’extraordinaire de CSS Grid:

.archive {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  grid-gap: 32px;
  grid-auto-flow: dense;
}

/* Extra-wide grid-posts */
.article:nth-child(31n + 1) {
  grid-column: 1 / -1;
}
.article:nth-child(16n + 2) {
  grid-column: -3 / -1;
}
.article:nth-child(16n + 10) {
  grid-column: 1 / -2;
}

/* Single column display for phones */
@media (max-width: 459px) {
  .archive {
    display: flex;
    flex-direction: column;
  }
}

Les techniques de cet article peuvent également être utilisées pour styliser tout contenu généré dynamiquement, comme la sortie d’un widget de publications récentes, de pages d’archives ou de résultats de recherche.

Créer une grille réactive

J’ai mis en place dix-sept éléments affichant une variété de contenus fictifs – titres, images et extraits – qui sont tous contenus dans un emballage

Le code qui transforme ces éléments en une grille réactive est remarquablement compact:

.archive {
  /* Define the element as a grid container */
  display: grid;
  /* Auto-fit as many items on a row as possible without going under 180px */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  /* A little spacing between articles */
  grid-gap: 1em;
}

Remarquez comment les hauteurs des lignes s’ajustent automatiquement pour s’adapter au contenu le plus haut de la ligne. Si vous modifiez la largeur du stylet, vous verrez les éléments croître et se rétrécir de manière fluide et le nombre de colonnes changer de un à cinq, respectivement.

La magie de la grille CSS en jeu ici est la auto-fit mot-clé qui fonctionne main dans la main avec le minmax() fonction qui est appliquée à grid-template-columns.

Comment ça fonctionne

Nous aurions pu réaliser la disposition à cinq colonnes seul en utilisant ceci:

.archive {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

Cependant, cela créerait cinq colonnes qui grandissent et rétrécissent avec différentes largeurs d’écran, mais restent toujours à cinq colonnes, ce qui les rend ridiculement étroites sur les petits écrans. La première pensée pourrait être de créer un tas de requêtes multimédias et de redéfinir la grille avec différents nombres de colonnes. Cela fonctionnerait bien, mais avec le auto-fit mot-clé, tout se fait automatiquement.

Pour que l’ajustement automatique fonctionne comme nous le voulons, nous devons utiliser le minmax() une fonction. Cela indique au navigateur à quel point les colonnes peuvent être réduites, suivies de la largeur maximale à laquelle elles peuvent s’étendre. Plus petit, il réduira automatiquement le nombre de colonnes. Plus grand et le nombre de colonnes augmente.

.archive {
  grid-template-columns: repeat (auto-fit, minmax(180px, 1fr));
}

Dans cet exemple, le navigateur tiendra dans autant de colonnes qu’il peut 180px de large. S’il reste de l’espace sur les colonnes, elles augmenteront toutes également en partageant l’espace restant entre elles – c’est ce que 1fr valeur dit: faire les colonnes des fractions égales de la largeur disponible.

Faites glisser la fenêtre vers l’extérieur et à mesure que l’espace disponible augmente, les colonnes s’agrandissent toutes de manière égale pour utiliser tout espace supplémentaire. Les colonnes continueront de croître jusqu’à ce que l’espace disponible permette une colonne supplémentaire de 180 pixels, auquel point une toute nouvelle colonne apparaîtra. Réduisez la largeur de l’écran et le processus s’inverse, en ajustant parfaitement la grille jusqu’à une disposition à une seule colonne. La magie!

Et vous obtenez toute cette réactivité d’une seule ligne de code. À quel point cela est cool?

Création de plages avec «autoflow: dense»

Jusqu’à présent, nous avons une grille réactive mais tous les articles ont la même largeur. Pour une mise en page d’actualités ou de magazines, nous avons besoin de contenu pour être présenté en couvrant deux colonnes ou plus ou même, peut-être, pour couvrir toutes les colonnes.

Pour créer des étendues à plusieurs colonnes, nous pouvons ajouter la fonctionnalité d’envergure aux colonnes aux éléments de la grille que nous voulons occuper plus d’espace. Par exemple, si nous voulons que le troisième élément de notre liste soit large de deux colonnes, nous pouvons ajouter:

.article:nth-child(3) {
  grid-column: span 2;
}

Cependant, une fois que nous commençons à ajouter des portées, un certain nombre de problèmes peuvent survenir. Tout d’abord, des espaces peuvent apparaître dans la grille car un élément large peut ne pas tenir sur la ligne, donc la grille auto-fit le pousse sur la ligne suivante, laissant un espace où il aurait été:

La solution facile consiste à ajouter grid-auto-flow: dense à l’élément de grille qui indique au navigateur de combler les lacunes avec d’autres éléments, ce qui rend le flux de contenu plus étroit autour des éléments plus larges comme ceci:

Notez que les articles sont maintenant hors service, le quatrième article précédant le troisième, qui est le double de la largeur. Il n’y a aucun moyen de contourner cela pour autant que je sache, et c’est l’une des limitations que vous devez accepter avec CSS Grid.

Consultez «Les pouvoirs auto-fluides du mot-clé dense de la grille» de Geoff Graham pour une introduction au flux automatique de la grille: dense avec des exemples de son comportement.

Façons de spécifier les portées

Il existe plusieurs façons d’indiquer le nombre de colonnes qu’un élément doit couvrir. Le plus simple est de postuler grid-columns: span [n] à l’un des éléments, où n est le nombre de colonnes que l’élément couvrira. Le troisième élément de notre mise en page a grid-column: span 2, ce qui explique pourquoi le double de la largeur des autres éléments ne couvre qu’une seule colonne.

D’autres méthodes vous obligent à définir explicitement des lignes de grille. Le système de numérotation des lignes de grille est le suivant:

Les lignes de la grille peuvent être spécifiées de gauche à droite en utilisant des valeurs positives (par exemple 1, 2, 3) ou des valeurs négatives (par exemple -1, -2, -3) pour aller de droite à gauche. Ceux-ci peuvent être utilisés pour placer des éléments sur la grille en utilisant la propriété grid-column comme ceci:

.grid-item {
  grid-column: (start track) / (end track);
}

Ainsi, cela nous donne des moyens supplémentaires de spécifier un élément fractionné. Ceci est particulièrement flexible car la valeur de début ou de fin peut être remplacée par le mot clé span. Par exemple, la boîte bleue à trois colonnes de l’exemple ci-dessus peut être créée en ajoutant l’un des éléments suivants au huitième élément de la grille:

  • grid-column: 3 / 6
  • grid-column: -4 / -1
  • grid-column: 3 / span 3
  • grid-column: -4 / span 3
  • grid-column: span 3 / -1
  • Etc.

Sur une grille non réactive (c’est-à-dire des colonnes fixes), elles produisent toutes le même effet (comme la boîte bleue ci-dessus), cependant, si la grille est réactive et que le nombre de colonnes change, leurs différences commencent à devenir apparentes. Certaines étendues de colonnes cassent la disposition avec une grille à écoulement automatique, ce qui rend les deux techniques incompatibles. Heureusement, il existe des solutions qui nous permettent de combiner les deux avec succès.

Mais d’abord, nous devons comprendre le problème.

Débordement des problèmes de défilement latéral

Voici quelques zones en vedette créées en utilisant la notation ci-dessus:

(Démo)

Tout semble bon en pleine largeur (cinq colonnes), mais lorsqu’il est redimensionné à ce qui devrait être deux colonnes, la disposition se brise comme suit:

Comme vous pouvez le voir, notre grille a perdu sa réactivité et, bien que le conteneur ait rétréci, la grille essaie de maintenir les cinq colonnes. Pour ce faire, il a renoncé à essayer de conserver des colonnes de largeur égale, et la grille se détache du côté droit de son conteneur, provoquant un défilement horizontal.

Pourquoi est-ce? Le problème vient du fait que le navigateur essaie d’honorer les lignes de grille explicites que nous avons nommées. À cette largeur, le auto-fit La grille devrait implicitement afficher deux colonnes, mais notre système de numérotation des lignes de grille contredit cela en faisant explicitement référence à la cinquième ligne de grille. Cette contradiction mène au gâchis. Pour afficher correctement notre grille implicite à deux colonnes, les seuls numéros de ligne autorisés sont 1, 2 et 3 et -3, -2, -1, comme ceci:

Mais si l’un de nos éléments de grille contient grid-column références qui se trouvent en dehors de cela, telles que la ligne de grille numéro 4, 5 ou 6 (ou -4, -5 ou -6), le navigateur reçoit des messages mitigés. D’une part, nous lui avons demandé de créer automatiquement des colonnes flexibles (ce qui devrait implicitement nous donner deux colonnes à cette largeur d’écran) mais nous avons également fait explicitement référence à des lignes de grille qui n’apparaissent pas dans une grille à deux colonnes. En cas de conflit entre des colonnes implicites (automatiques) et un nombre explicite de colonnes, grille renvoie toujours à la grille explicite; d’où les colonnes indésirables et le débordement horizontal (qui a également été nommé à juste titre perte de données CSS). Tout comme l’utilisation de numéros de ligne de grille, les étendues peuvent également créer des colonnes explicites. Donc, grid-column: span 3 (le huitième élément de la grille dans la démo) force la grille à adopter explicitement au moins trois colonnes, alors que nous le voulons, en afficher implicitement deux.

À ce stade, il peut sembler que la seule façon d’aller de l’avant consiste à utiliser les requêtes multimédias pour modifier les valeurs de la colonne de la grille à la largeur où notre disposition se casse – mais pas si vite! C’est ce que j’ai supposé au début. Mais après y avoir réfléchi un peu plus et avoir joué avec diverses options, j’ai constaté qu’il existe un ensemble limité de solutions de contournement qui fonctionnent jusqu’à deux colonnes, laissant une seule requête multimédia pour couvrir une disposition de colonne unique pour les écrans les plus étroits.

Les solutions

L’astuce, je m’en suis rendu compte, consiste à spécifier uniquement les étendues en utilisant des lignes de grille qui apparaissent dans la grille la plus étroite que vous avez l’intention d’afficher. C’est une grille à deux colonnes dans ce cas. (Nous utiliserons une requête multimédia pour couvrir le scénario à colonne unique pour des écrans très étroits.) Cela signifie que nous pouvons utiliser en toute sécurité les lignes de grille 1, 2 et 3 (ou -3, -2 et -1) sans casser la grille.

J’ai d’abord pensé que cela signifiait me limiter à une portée maximale de deux colonnes, en utilisant des combinaisons des éléments suivants:

  • grid column: span 2
  • grid-column: 1 /3
  • grid-column: -3 / -1

Ce qui reste parfaitement réactif jusqu’à deux colonnes:

Bien que cela fonctionne, il est plutôt limitatif du point de vue du design, et pas particulièrement excitant. Je voulais pouvoir créer des portées de trois, quatre ou même cinq colonnes de large sur de grands écrans. Mais comment? Ma première pensée a été de devoir recourir aux requêtes des médias (les vieilles habitudes d’OMG ont la vie dure!), Mais j’essayais de m’éloigner de cette approche et de penser différemment la conception réactive.

En examinant à nouveau ce que nous pouvons faire avec seulement 1 à 3 et -3 à -1, je me suis progressivement rendu compte que je pouvais mélanger des numéros de ligne positifs et négatifs pour les valeurs de début et de fin de la colonne de grille, telles que 1/-3 et 2/-2. À première vue, cela ne semble pas très intéressant. Cela change lorsque vous réalisez où ces lignes sont situées lorsque vous redimensionnez la grille: ces éléments étendus changent de largeur avec la taille de l’écran. Cela a ouvert un tout nouvel ensemble de possibilités pour des étendues de colonnes réactives: des éléments qui couvriront différents nombres de colonnes à mesure que l’écran s’élargit, sans avoir besoin de requêtes multimédias.

Le premier exemple que j’ai découvert est la grille-colonne: 1/-1Cela fait que l’élément se comporte comme une bannière pleine largeur, s’étendant de la première à la dernière colonne pour tous les numéros de colonne. cela fonctionne même jusqu’à une colonne de large!

En utilisant grid-column: 1/-2, un intervalle presque pleine largeur aligné à gauche pourrait être créé qui laisserait toujours un élément d’une colonne à sa droite. Réduit à deux colonnes, il rétrécit en réponse à une seule colonne. Étonnamment, il fonctionne même lorsqu’il est réduit à une disposition à une seule colonne. (La raison semble être que la grille ne réduira pas un élément à une largeur nulle, il reste donc une colonne de large, tout comme grid-column: 1/1.) Je supposais grid-column: 2/-1 fonctionnerait de la même manière, mais aligné avec le bord droit, et pour la plupart, il le fait, sauf sur un affichage de colonne lorsqu’il provoque un débordement.

Ensuite j’ai essayé 1/-3 qui fonctionnait bien sur un écran plus large, montrant au moins trois colonnes, et des écrans plus petits, montrant une colonne. Je pensais que cela ferait quelque chose de bizarre sur une grille à deux colonnes car la première ligne de grille est la même que la ligne de grille avec -3. À ma grande surprise, il s’affiche toujours comme un élément à une seule colonne.

Après avoir beaucoup joué, j’ai trouvé onze valeurs de colonne de grille possibles en utilisant les numéros de ligne de grille de la grille à deux colonnes. Étonnamment, trois d’entre eux fonctionnent jusqu’à des dispositions à une seule colonne. Sept autres fonctionnent sur deux colonnes et n’auraient besoin que d’une seule requête média pour gérer l’affichage sur une seule colonne.

Voici la liste complète:

Valeurs de grille réactives, montrant comment elles s’affichent à différentes tailles d’écran dans un auto-fit la grille. (Démo)

Comme vous pouvez le voir, bien qu’il s’agisse d’un sous-ensemble limité de toutes les plages réactives possibles, il existe en fait de nombreuses possibilités.

  • 2/-2 est intéressant car il crée une plage centrée qui fonctionne jusqu’à une colonne!
  • 3/-1 est moins utile car il provoque un débordement même avec deux colonnes.
  • 3/-3 était une surprise.

En utilisant une variété de grid-column valeurs de cette liste, il est possible de créer une mise en page intéressante et entièrement réactive. En utilisant une seule requête multimédia pour l’affichage sur une seule colonne le plus étroit, nous avons dix différents grid-column modèles de durée pour jouer avec.

La requête multimédia sur une seule colonne est généralement aussi simple. Celui de cette démo finale revient à utiliser Flexbox sur des écrans plus petits:

@media (max-width: 680px) {
  .archive {
    display: flex;
    flex-direction: column;
  }

  .article {
    margin-bottom: 2em;
  }
}

Voici la grille finale qui, comme vous pouvez le voir, est entièrement réactive d’une à cinq colonnes:

(Démo)

Utilisation de: nth-child () pour répéter les affichages de longueur variable

La dernière astuce que j’ai utilisée pour réduire mon code à deux douzaines de lignes était la :nth-child(n) sélecteur que j’ai utilisé pour styliser plusieurs éléments dans ma grille. Je voulais que mon style de portée s’applique à plusieurs éléments de mon flux, afin que les boîtes aux lettres présentées apparaissent régulièrement tout au long de la page. Pour commencer, j’ai utilisé une liste de sélection séparée par des virgules, comme ceci:

.article:nth-child(2),
.article:nth-child(18),
.article:nth-child(34),
.article:nth-child(50)  {
  background-color: rgba(128,0,64,0.8);
  grid-column: -3 / -1;
}

Mais j’ai vite trouvé cela encombrant, d’autant plus que je devais répéter cette liste pour chaque élément enfant que je voulais styliser dans chaque article – comme le titre, les liens, etc. Pendant le prototypage, si je voulais jouer avec la position de mes éléments étendus, je devais changer manuellement les nombres dans chacune de ces listes, ce qui était fastidieux et sujet aux erreurs.

C’est à ce moment que j’ai réalisé que je pouvais utiliser une fonctionnalité puissante :nth-child pseudo-sélecteur au lieu d’un simple entier comme je l’avais utilisé dans la liste ci-dessus. :nth-child(n) peut également prendre une équation, telle que :nth-child(2n+ 2), qui ciblera chaque deuxième élément enfant.

Voici comment j’ai utilisé le :nth-child([formula]) pour créer les panneaux bleus pleine largeur dans ma grille qui apparaissent tout en haut de la page et se répètent un peu plus à mi-chemin:

.article:nth-child(31n + 1) {
  grid-column: 1 / -1;
  background: rgba(11, 111, 222, 0.5);
}

Le bit entre crochets (31n + 1 ) garantit que le 1st, 32Dakota du Nord, 63rd, etc. enfant est sélectionné. Le navigateur exécute une boucle commençant par n = 0 (auquel cas 31 * 0 + 1 = 1), puis n=1 (31 * 1 + 1 = 32), puis n=2 (31 * 2 + 1 = 63). Dans le dernier cas, le navigateur se rend compte qu’il n’y a pas de 63rd élément enfant afin qu’il ignore cela, arrête la boucle et applique le CSS au 1st et 32Dakota du Nord les enfants.

Je fais quelque chose de similaire pour les cases violettes qui alternent de bas en haut de la page:

.article:nth-child(16n + 2) {
  grid-column: -3 / -1;
  background: rgba(128, 0, 64, 0.8);
}

.article:nth-child(16n + 10) {
  grid-column: 1 / -2;
  background: rgba(128, 0, 64, 0.8);
}

Le premier sélecteur concerne les cases violettes de droite. le 16n + 2 s’assure que le style s’applique à tous les 16e élément de grille, en commençant par le deuxième élément.

Le deuxième sélecteur cible les cases de droite. Il utilise le même espacement (16n) mais avec un décalage différent (10). Par conséquent, ces cases apparaissent régulièrement sur le côté droit pour les éléments de grille 10, 26, 42, etc.

En ce qui concerne le style visuel de ces éléments de la grille et de leur contenu, j’ai utilisé une autre astuce pour réduire la répétition. Pour les styles partagés par les deux cases (tels que background-color, par exemple), un seul sélecteur peut être utilisé pour cibler à la fois:

.article:nth-child(8n + 2) {
  background: rgba(128, 0, 64, 0.8);
  /* Other shared syling */
}

Cela visera les éléments 2, 10, 18, 26, 34, 42, 50, etc. En d’autres termes, il sélectionne les cases en vedette à gauche et à droite.

Cela fonctionne parce que 8n est exactement la moitié de 16n, et parce que les décalages utilisés dans les deux sélecteurs séparés ont une différence de 8 (c’est-à-dire que la différence entre +10 et +2 est de 8)

Dernières pensées

À l’heure actuelle, CSS Grid peut être utilisé pour créer des grilles réactives flexibles avec un code minimal, mais cela comporte des limitations importantes sur le positionnement des éléments sans l’étape rétrograde d’utilisation des requêtes multimédias.

Ce serait formidable de pouvoir spécifier des plages qui ne forceraient pas le débordement sur des écrans plus petits. Pour le moment, nous disons effectivement au navigateur: «Créez une grille réactive, s’il vous plaît», ce qu’il fait magnifiquement. Mais lorsque nous continuons en disant: «Oh, et que cet élément de grille s’étende sur quatre colonnes», il lance un sifflement sur des écrans étroits, donnant la priorité à la demande d’étendue à quatre colonnes plutôt qu’à la grille réactive. Ce serait formidable de pouvoir dire à grid de prioriser la réactivité par rapport à notre demande de durée. Quelque chose comme ça:

.article {
  grid-column: span 3, autofit;
}

Un autre problème avec les grilles réactives est la dernière ligne. Comme la largeur de l’écran change, la dernière ligne n’est souvent pas remplie. J’ai passé beaucoup de temps à chercher un moyen de faire en sorte que le dernier élément de la grille s’étende (et donc remplisse) les colonnes restantes, mais il semble que vous ne puissiez pas le faire dans la grille pour le moment. Ce serait bien si nous pouvions spécifier la position de départ de l’élément avec un mot-clé comme la signification automatique, “Veuillez laisser le bord gauche partout où il tombe.” Comme ça:

.article {
  grid-column: auto, -1;
}

… Ce qui prolongerait le bord gauche jusqu’à la fin de la ligne.

Close Menu