Search code examples
csscss-grid

How to stack unknown number of generic content items in a CSS Grid template area


I haven't quite got my head around grid-template-areas, I suspect. Or maybe I do, but it is the behaviour of direct Grid descendant nodes that do not have a grid-area assigned.

Here is visually what I am trying to achieve:

visual example of desired outcome

Codepen is here: https://codepen.io/davewallace/pen/abYxWxE

Similar code example:

html, body , .container {
  height: 100%;
  margin: 0;
}

.container {
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: 1fr max-content;
  gap: 40px 40px;
  grid-template-areas:
    "header header"
    ". graphic";
}
.header { grid-area: header; }
.graphic { grid-area: graphic; }

/* For presentation only, no need to copy the code below */
.container * {
  border: 1px solid red;
  position: relative;
}
<div class="container">
  <div class="header">Full-width title</div>
  <div class="graphic">Graphic</div>
  <h4>Random element here</h4>
  <p>Random element here</p>
  <p>Random element here</p>
</div>

I seem to be able to only achieve two things currently:

  1. Everything is in the right place, but all "generic content items" overlap on top of each other, where instead I want them stacked.
  2. The title is in the right place, the image is sort of in the right place, but columns and/or rows are added automatically and do things like wrap under the image

The MDN docs for grid-template-area haven't really cleared the mix of behaviours up for me. I also tried using https://grid.layoutit.com/ to visualise the layout, and that seemed to get me off to a good start, but the default behaviour of the generic nodes has me confused.


Solution

  • You can approximate it like below:

    body {
      margin: 0;
    }
    
    .container {
      min-height: 100vh;
      display: grid;
      grid-template-columns: 1fr max-content;
      grid-auto-flow: dense;
      gap: 0 40px; /* set only column gap */
    }
    
    .header {
      grid-row: 1;
      grid-column: 1/-1;
    }
    
    .graphic {
      grid-column: 2;
      grid-row: 2/ span 100; /* this will do the trick */
    }
    
    .container *:not(.graphic,:last-child) {
      margin-bottom: 40px; /* replace the row gap */
    }
    
    
    /* For presentation only, no need to copy the code below */
    
    .container * {
      border: 1px solid red;
      position: relative;
      margin: 0;
    }
    <div class="container">
      <div class="header">Full-width title</div>
      <div class="graphic">Some Graphic here</div>
      <h4>Random element here</h4>
      <p>Random element here</p>
      <p>Random element here</p>
    </div>