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:
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.
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>