web-dev-qa-db-fra.com

Hauteur égale des éléments à l'intérieur de l'élément de grille avec une disposition de grille CSS

J'ai une séquence d'articles à l'intérieur d'un div de longueur 4+, sans balise de ligne d'arrondi. Je dois le représenter comme un tableau de 3 articles (colonnes) par ligne, probablement avec display: grid. Chaque article a un en-tête, une section et un pied de page.

Comment pourrais-je implémenter une hauteur égale pour chaque en-tête, une hauteur égale pour chaque section et un pied de page de hauteur égale, alignés sur le bas de l'article, à l'intérieur de chaque ligne d'articles? Est-ce même possible? Dois-je utiliser display: table?

PS Je dois changer dynamiquement le nombre d'articles par ligne, en fonction de la largeur de l'écran. Merci.

HTML:

body {
  width: 100%;
  max-width: 1024px;
  margin: auto;
}

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

.container article {
  display: grid;
}

article header {
  background-color: #eeeeee;
}

article section {
  background-color: #cccccc;
}

article footer {
  background-color: #dddddd;
}
<div class="container">
  <article>
    <header>
      <h2>Header</h2>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
    </footer>
  </article>
  <article>
    <header>
      <h2>Header</h2>
    </header>
    <section>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
      <p>Content</p>
    </section>
    <footer>
      <p>Footer</p>
      <p>Footer</p>
    </footer>
  </article>
</div>

NB: JS est obsolète.

https://codepen.io/yudnikov/pen/mBvbGW?editors=1100#

Cette solution :

grid-auto-rows: 1fr; 

a été proposé en double, ce qui n'est pas le cas. Il ne donnera aux articles une hauteur égale, tandis que par ex. les en-têtes de chaque article restent de taille différente.

J'ai eu à l'origine ce problème:

This is what I'am talking about

Et le grid-auto-rows: 1fr la solution aboutit à ceci:

Wrong!

12
Igor Yudnikov

Est-ce même possible?

tldr; Oui.

Codepen Demo # 1

Codepen Demo # 2 (Utilise SASS et est configurable)


Il y a en fait un moyen de retirer cela avec des grilles CSS et sans changer le balisage!

Nous pourrions "aplatir" la structure avec CSS de sorte que tous les composants de tous les articles fassent partie d'une seule grille CSS - le conteneur d'article.

Cela est possible sans même modifier le balisage actuel en définissant les articles avec display: contents

affichage: conten ( caniuse )

De Caniuse :

display: contents fait apparaître les enfants d'un élément comme s'ils étaient les enfants directs du parent de l'élément, ignorant l'élément lui-même. Cela peut être utile lorsqu'un élément wrapper doit être ignoré lors de l'utilisation d'une grille CSS ou de techniques de mise en page similaires.

Donc, si nous définissons les articles avec display: contents

.container article {
  display: contents;
}

Maintenant, tous les en-têtes, sections et pieds de page deviennent des éléments de grille (directs) (du conteneur - qui a display:grid) que nous pouvons organiser en utilisant le grid-template-areas propriété.

.container {
  display: grid;
  grid-column-gap: 1em; /* horizontal gap between articles */
  grid-template-columns: repeat(3, 1fr);

  grid-template-areas: "header1 header2 header3" 
                       "section1 section2 section3"
                       "footer1 footer2 footer3"
                       "header4 header5 header6" 
                       "section4 section5 section6"
                       "footer4 footer5 footer6"
}

Étant donné que chaque en-tête/section/pied de page occupe exactement une cellule - cela les oblige à occuper la même hauteur verticale . Donc par exemple header1, header2 et header3 auront tous la même hauteur quel que soit leur contenu.

Maintenant, définissez le grid-area propriétés sur chacune des cellules.

article:nth-child(1) header {
  grid-area: header1;
}
article:nth-child(2) header {
  grid-area: header2;
}
article:nth-child(3) header {
  grid-area: header3;
}
article:nth-child(4) header {
  grid-area: header4;
}
article:nth-child(1) section {
  grid-area: section1;
}
...
article:nth-child(4) section {
  grid-area: section4;
}
article:nth-child(1) footer {
  grid-area: footer1;
}
...
article:nth-child(4) footer {
  grid-area: footer4;
}

Enfin, définissez un écart vertical entre chaque ligne d'articles (à partir de la deuxième ligne d'articles):

article:nth-child(n + 4) header {
  margin-top: 1em;
}

Démo:

body {
  width: 100%;
  max-width: 1024px;
  margin: auto;
}

.container {
  display: grid;
  grid-column-gap: 1em;
  grid-template-columns: repeat(3, 1fr);
  grid-template-areas: "header1 header2 header3" 
                      "section1 section2 section3"
                        "footer1 footer2 footer3"
                        "header4 header5 header6" 
                      "section4 section5 section6"
                        "footer4 footer5 footer6"
}

.container article {
  display: contents;
}

article header {
  background-color: #eeeeee;
}

article section {
  background-color: #cccccc;
}

article footer {
  background-color: #dddddd;
}

article:nth-child(n + 4) header {
  margin-top: 1em;
}

article:nth-child(1) header {
  grid-area: header1;
}
article:nth-child(2) header {
  grid-area: header2;
}
article:nth-child(3) header {
  grid-area: header3;
}
article:nth-child(4) header {
  grid-area: header4;
}
article:nth-child(1) section {
  grid-area: section1;
}
article:nth-child(2) section {
  grid-area: section2;
}
article:nth-child(3) section {
  grid-area: section3;
}
article:nth-child(4) section {
  grid-area: section4;
}
article:nth-child(1) footer {
  grid-area: footer1;
}
article:nth-child(2) footer {
  grid-area: footer2;
}
article:nth-child(3) footer {
  grid-area: footer3;
}
article:nth-child(4) footer {
  grid-area: footer4;
}
<div class="container">
    <article>
        <header>
            <h2>Header</h2>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
        </footer>
    </article>
    <article>
        <header>
            <h2>Header</h2>
        </header>
        <section>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
            <p>Content</p>
        </section>
        <footer>
            <p>Footer</p>
            <p>Footer</p>
        </footer>
    </article>
</div>

Démo Codepen)

Bien sûr, au lieu d'utiliser le grid-template-areas + grid-area propriétés que nous pourrions utiliser à la place grid-row + grid-column propriétés pour obtenir le même résultat - démo Codepen


Remarque: Je me rends compte que ce qui précède est détaillé et pas exactement une solution optimale - mais mon point ici est que c'est possible . Aussi, nous pourrions utiliser des boucles SASS pour rendre ce code beaucoup plus propre et également configurable .

Ce serait bien s'il y avait un moyen de répéter un motif en utilisant grid-template-areas - quelque chose comme:

pseudo-code (non légal):

grid-template-areas: repeat("header1 header2 header3" 
                           "section1 section2 section3"
                           "footer1 footer2 footer3")

... alors nous pourrions obtenir une solution plus dynamique qui fonctionnerait pour la solution n articles en définissant la zone de la grille en utilisant nth-child comme:

article:nth-child(3n + 1) header {
  grid-area: header1;
} 

etc ... mais je ne pense pas que ce soit possible pour le moment (ou peut-être que ce n'est pas nécessaire parce que sous-grilles pourra le faire?)


NB:

Le module de disposition de grille de niveau 2 introduit sous-grilles qui rendra ce problème plus facile à résoudre et sans avoir à utiliser display: contents


Dois-je utiliser display: table?

Pour la mise en page dont vous avez besoin - display:table n'aidera pas beaucoup. Tout d'abord, vous devez restructurer totalement votre balisage pour regrouper les composants d'article ensemble comme apposé aux articles, vous devez pirater pour styliser le tableau pour ressembler à des "articles", mais même dans ce cas - les tableaux ne s'emballent pas, vous devez donc envelopper tous les trois articles dans un tableau séparé ... même si c'était possible, ce serait vraiment compliqué et difficile à gérer.

10
Danield