Search code examples
csscss-grid

CSS Grid vs dynamic definition list autoplacement


Disclaimer: According to the spec, one could wrap dt + dd pairs into a div, which would allow me to trivially solve my problem using either float and clear, flexbox or even CSS grid.

There are also alternatives like this that wraps each group of 2 dt + dd pairs into separate ul tags. This also works, even though it's not 100% semantically accurate.

Now what I am really trying to do is to find a solution for the problem using CSS grid, without resorting to any of the above techniques.


I have the following structure in my HTML:

dl
  dt
  dd

  dt
  dd

  dt
  dd

  dt
  dd

  ...

I want to display them grouped in 2 columns and 2 rows like this:

dt    dt
dd    dd

dt    dt
dd    dd

..    ..

I managed to find a solution for the case when I have 4 pairs and want to display them in a 2x2 grid:

body {
  font-family: sans-serif;
}

dl {
  display: grid;
  grid-gap: 0 1rem;
  grid-template-columns: [col] 1fr [col] 1fr [col];
  grid-template-rows: repeat(auto-fill, 1fr);
  text-align: center;
}

dt {
  padding: 0.25rem 1rem;
  background: lightcoral;
}

dt:nth-of-type(2n + 1) {
  counter-increment: left;
  grid-column: col 1 / span 1;
}

dt:nth-of-type(2n) {
  counter-increment: right;
  grid-column: col 2 / span 1;
}


/* Comment out the following 2 selectors to see the "automatic behavior */

dt:nth-of-type(2) {
  grid-row: 1;
}

dt:nth-of-type(4) {
  grid-row: 3;
}


/* /Comment out */

dd {
  margin: 0 0 1rem;
  padding: 0.25rem 1rem;
  background: lightcyan;
}

dd:nth-last-of-type(-n + 2) {
  margin-bottom: 0;
}

dd:nth-of-type(2n + 1) {
  grid-column: col 1 / span 1;
}

dd:nth-of-type(2n) {
  grid-column: col 2 / span 1;
}
<!DOCTYPE html>
<html>

<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" type="text/css" href="src/styles.css" />
</head>

<body>
  <div id="app">
    <dl>
      <dt>Item 1</dt>
      <dd>Nunc ut quam at sem vehicula hendrerit sed vitae risus</dd>
      <dt>Item 2</dt>
      <dd>
        uisque a maximus mauris. Quisque metus quam, auctor ac porttitor.
      </dd>
      <dt>Item 3</dt>
      <dd>
        Aliquam varius est ac lectus malesuada, a sagittis arcu laoreet.
      </dd>
      <dt>Item 4</dt>
      <dd>Etiam et sapien at mi ultrices maximus vitae vel arcu.</dd>
    </dl>
  </div>
</body>

</html>

However, that only works because I'm manually defining the row in which specific dt elements should sit on:

dt:nth-of-type(2) {
  grid-row: 1;
}

dt:nth-of-type(4) {
  grid-row: 3;
}

Without this I would get:

Grid Autoplacement Issue

The row placement for the items on the right is off by 1.

Is there a way to "shift" the value of grid-row by -1 in a general fashion?

I also tried to pair grid-row value with counter, but it looks like this is unsupported.


Solution

  • This is the purpose of grid-auto-flow: dense

    If specified, the auto-placement algorithm uses a “dense” packing algorithm, which attempts to fill in holes earlier in the grid if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items. ref

    I have also simplified the code a litte:

    body {
      font-family: sans-serif;
    }
    
    dl {
      display: grid;
      grid-gap: 0 1rem;
      grid-template-columns: 1fr 1fr;
      text-align: center;
      grid-auto-flow: dense;
    }
    
    dt {
      padding: 0.25rem 1rem;
      background: lightcoral;
    }
    dl > :nth-of-type(2n + 1) {
      grid-column: 1;
    }
    
    dl > :nth-of-type(2n) {
      grid-column: 2;
    }
    
    dd {
      margin: 0 0 1rem;
      padding: 0.25rem 1rem;
      background: lightcyan;
    }
    
    dd:nth-last-of-type(-n + 2) {
      margin-bottom: 0;
    }
      <div id="app">
        <dl>
          <dt>Item 1</dt>
          <dd>Nunc ut quam at sem vehicula hendrerit sed vitae risus</dd>
          <dt>Item 2</dt>
          <dd>
            uisque a maximus mauris. Quisque metus quam, auctor ac porttitor.
          </dd>
          <dt>Item 3</dt>
          <dd>
            Aliquam varius est ac lectus malesuada, a sagittis arcu laoreet.
          </dd>
          <dt>Item 4</dt>
          <dd>Etiam et sapien at mi ultrices maximus vitae vel arcu.</dd>
        </dl>
      </div>