Niveau Niveau confirmé

Grid Layout et positionnement absolu

Tutorielcss

Publié par le (12442 lectures)

css layout grid gridlayout

Si Grid Layout nous permet aujourd’hui de créer des designs fluides et responsive de manière très simple et permettant de favoriser la sémantique et la lisibilité de notre HTML, saviez vous que cette propriété CSS fonctionne également très bien avec des enfants en position absolue ?

Ma grille de base

Une des forces de Grid Layout est de pouvoir créer un motif de ligne qui va se répéter dès qu’elle sera pleine. Pour le design de mon site, disons que mon graphiste travaille avec une grille de 12 colonnes. Je vais donc créer ma ligne de grille de base :

<body>
  <section class="grid">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ...
  </section>
</body>
body {
  padding: 2.5rem;
  background-color: AntiqueWhite;
}

* { 
  box-sizing: border-box;
}

.grid {
  display: grid;
  grid-gap: 1.5rem;
  grid-template-columns: repeat(12, 1fr);
}

.item {
  padding: 1.5rem 0;
  background-color: coral;
}

Ma grille simple de 12 colonnes

Comme on le constate, par défaut, si j’ai plus de 12 objets, grid va créer une nouvelle ligne de 12 colonnes et ainsi de suite. Tous les éléments de grilles générés ainsi sont appelés grille implicite. Nous en verrons l'intérêt plus tard.

En passant, petite astuce pour vous simplifier la vie lorsque vous travaillez avec les grilles en CSS. Si vous avez un navigateur digne de ce nom, vous devriez pouvoir afficher un overlay d'aperçu de votre grille en cliquant sur un de ces boutons dans votre inspecteur:

Afficher ma grille dans l'inspecteur du navigateur

Voyons un cas concret

Notre graphiste nous donne ce très beau bloc à intégrer.

Mon beau design

On peut découper cette maquette en 3 blocs de contenus qui vont apparaitre dans ma grille :

  • Un bloc de titre
  • Un bloc de texte
  • Un bloc illustration

Ce qui nous donne le code html suivant :

<body>
  <section class="grid">
    <h1  class="item text-content">Titre</h1>
    <p   class="item text-content">Texte</p>
    <div class="item illustration">Illus.</div>
  </section>
</body>

Jusqu'ici pas de pépins, passons au style.

Contenu textuel

Le titre et le texte commencent à la première colonne de la grille et font 8 colonnes de large. Vu que grid génère automatiquement des lignes en fonction du contenu, le bloc <p class="item text-content">Texte</p> va se trouver dans une nouvelle ligne de la grille. Pas besoin donc de spécifier de grid-row pour ces blocs la.

.text-content {
  grid-column: 1 / span 8;
}

Contenu illustrationnel

Le bloc illustration commence à la colonne 9 et fait 4 colonnes de large. Il est aussi haut que le titre et le texte, donc il doit prendre 2 lignes de ma grille. Voici le code que l'on ajoute:

.illustration {
  grid-column: 9 / span 4;
  grid-row: 1 / span 2;
}

Voilà le résultat:

Nos blocs mis en forme

Versions alternatives

Petit aparté: grid nous permet d'écrire les choses de différentes manières. Par exemple si j'avais énoncé ma problématique autrement, j'aurais pu dire que les blocs de texte commençaient à la colonne 1 et finissaient à la 9. Ou encore que le bloc d'illustration faisait 4 colonnes de large et terminait à la dernière colonne.

.text-content {
  grid-column: 1 / 9;
}

.illustration {
  grid-column: span 4 / -1;
  grid-row: 1 / 3;
}

Le rendu sera exactement le même, c'est simplement une autre façon de faire. Il n'y a pas de meilleur manière de l'écrire, le tout est de rester cohérent. Enoncer le comportement que doit avoir un bloc comme nous l'avons fait est une bonne manière de procéder.

Web is about flexibility

Super, nous sommes arrivés à nos fins (je vous fait volontairement fi de la couche graphique, ici c'est la grille qui nous intéresse). Après une petite démo notre graphiste est satisfait·e et nous soumet les déclinaisons suivantes :

Mon beau design décliné

En clair, quel que soit le nombre de blocs de texte, notre image doit toujours faire toute la hauteur de ces derniers (et donc de la grille). Pas de soucis, grid est un outil très puissant, voyons comment se comporte notre code en l'état.

Si j'ajoute un paragraphe :

layout avec deux paragraphes

Si je laisse uniquement le titre :

layout avec titre uniquement

On est plutôt pas mal, vu qu'on ajoute la classe .text-content à nos blocs textuels, ils occuperont toujours le même espace de la grille, créant ainsi de nouvelles lignes et ainsi de suite. Notre bloc illustration quant à lui commence à la ligne 1 de la grille et prend actuellement 2 lignes de haut, il faudrait pouvoir le faire commencer à la première et finir à la dernière ligne. On pourrait se dire que grid-row : 1 / -1 pourrait faire l'affaire mais il n'en est rien. Pourquoi donc ?

Tout simplement parce qu'une valeur de -1 à grid-row-end va cibler la dernière ligne explicite de la grille. Je vous le rappelle, ici c'est le contenu qui fait la grille, vu que les lignes ne sont pas définies (avec grid-templates-rows par exemple), les lignes sont générées. Il s'agit donc de lignes implicites. Pourquoi définir un nombre de lignes alors qu'on ignore encore la quantité de contenu qu'elles vont accueillir ? Que faire dans ce cas ?

Positionnement absolu à la rescousse !

La solution la plus simple pour nous va être de positionner notre bloc d'illustration en absolu par rapport à la grille. Ajoutons donc le code suivant à notre css et observons le résultat:

.grid {
  ...
  position: relative;
}
.illustration {
  ...
  position: absolute;
}

Bien que notre bloc soit positionné de manière absolue dans notre grille, il a quand même l'air de bien se placer par rapport à ses confrères. Pourtant il est bien sensé être positionné par défaut en haut à gauche de son conteneur relatif le plus proche, alors pourquoi ne se superpose-t-il pas avec notre bloc de titre? What sorcery is this?

Mon référentiel de positionnement absolu dans la grille

En fait c'est plutôt simple à comprendre. Dans une grille, le référentiel d'un element en absolu est défini en largeur par grid-column-start et grid-column-end s'ils sont renseignés. Mon left: 0 correspondra donc ici au début de ma colonne numéro 9, plutôt intéressant non ?

En prenant compte de cette information, je vais ajouter le code suivant à mon bloc illustration:

.illustration {
  ..
  left: 0; 
  top: 0;
  right: 0;
  bottom: 0;
}

Il prendra donc toute la largeur de 4 colonnes en commençant à la colonne 9. Qu'en est-il de la hauteur ? Le bloc va-t-il prendre toute la hauteur de ma grille ? Non mais presque. Comme je l'ai expliqué, si le referentiel est défini en largeur par les propriétés grid-column, il en est de même pour la hauteur avec grid-row: actuellement notre bloc commence à la première ligne et prend deux lignes. Son référentiel bas est donc le bas de la deuxième ligne de la gille. En supprimant la propriété grid-row je lui rend son référentiel en hauteur par défaut à savoir le haut et le bas de ma grille.

C'est gagné, mon élément prendra bien toute la hauteur de sa grille, peu importe le nombre de lignes. De plus nous n'aurons pas à craindre que du contenu textuel soit recouvert vu qu'ils s'arrêtent tous à la fin de la 8eme colonne. Voici un codepen avec le code final. N'hésitez pas à vous l'approrier et tester par vous même.

See the Pen Etape 3 : mon illustration en absolue by olivierstl (@olivierstl) on CodePen.

Pour aller plus loin

Nous avons abordé ici une intégration d'une maquette assez simple avec certaines des nouvelles propriétés qui gravitent autour des spécifications Grid Layout mais nous n'avons fait qu'effleurer la surface. La manière d'utiliser les grilles que je vous ai présenté n'est qu'une des nombreuses manière d'intégrer notre bloc.

Définir les lignes de notre grille

Pour le moment, la grille génère de nouvelles lignes automatiquement lorsque c'est nécessaire. Il est possible de renseigner une hauteur minimale et maximale pour ces lignes par exemple. Ici on définit la taille d'une ligne de grille créée de façon implicite en lui disant qu'elle doit faire au minimum 3rem de haut et au maximum, la taille de son contenu.

.grid {
  ...
  grid-auto-rows: minmax(3rem, auto);
}

Afficher notre image dans notre bloc illustration

Avec notre bloc illustration étirable, le portrait de notre cher Nicolas Cage risque d'être quelque peu déformé et maltraité. Nous pourrions utiliser une background-image et appliquer background-size afin que notre image prenne bien la taille de son conteneur mais on perdrait la possibilité d'avoir une image qui pourrait s'avérer sémantiquement nécessaire dans notre html. Comment faire donc ? Mais avec la propriété super chouette object-fit pardi !

<div class="item illustration">
  <img src="https://tinyurl.com/y5ehdyup" alt="Nicolas FTW">
</div>
.illustration img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Ici on spécifie à l'image qu'elle doit prendre 100% de son conteneur en hauteur et largeur. Ensuite object-fit va fonctionner comme background-size et évitera à l'image de se déformer. Résultat, aucune espace vide, elle est pas plus belle la vie ? Vous noterez que j'ai supprimé le padding sur le bloc illustration pour être sur que l'image arrive aux bords du bloc.

See the Pen Etape bonus : Nicolas ftw by olivierstl (@olivierstl) on CodePen.

Image à la une par Simone Hutsch sur Unsplash

Commentaires

J'ai eu des problèmes en essayant de mettre à jour le plugin - une erreur fatale s'est produite. C'est déjà arrivé deux fois. La première fois, je l'ai supprimé et installé à nouveau. Mais je veux trouver la solution au lieu d'une suppression répétée. Je l'ai désactivé et activé et j'ai eu l'erreur suivante: le plug-in n'a pas pu être activé car il a déclenché une erreur fatale - Rapport et étude de cas sur https://stackoverflow.com/questions/50141796/app-crashing-in-the-part-of-grid-layout-declaration https://writemyessaytoday.net/

J'ai un multisite sur WordPress 4.9.8

J'ai installé le plugin. Avec menu déroulant et méga menu - disposition standard, cela fonctionne bien. Mais avec la mise en page de grille de menu méga, je ne deviens qu'un site https://writemyessaytoday.net/ vide. Je ne vois que le logo de l'entreprise et la bordure inférieure de l'en-tête.

Commenter

Vous devez être inscrit et identifié pour utiliser cette fonction.

Connectez-vous (déjà inscrit)

Oubli de mot de passe ? Pas de panique, on va le retrouver

Pas encore inscrit ? C'est très simple et gratuit.