Given a markup:
dl
dt
dd
dd
..
dt
dd
dd
...
I'm trying to achieve the following layout with CSS grid:
dt dt
dd dd dd dd
dd dd dd dd
dd dd dd dd
dd dd dd dd
My current approach is:
.time-table {
display: grid;
grid-gap: 1em;
grid-template-columns: repeat(4, 1fr);
grid-template-areas:
"destination1 destination1 destination2 destination2"
"time time time time";
list-style: none;
padding: 0;
}
.time-table__time {
background-color: #34ace0;
display: block;
color: #fff;
margin: 0;
grid-area: time;
}
.time-table__destination::before {
content: '\021D2';
display: inline-block;
transform: translateX(-5px);
}
.time-table__destination1 {
grid-area: destination1;
}
.time-table__destination2 {
grid-area: destination2;
}
@media (max-width: 35em) {
.time-table {
grid-template-columns: repeat(2, 1fr);
grid-template-areas:
"destination1 destination2"
"time time";
}
.time-table__destination::before {
transform: translateX(-5px);
}
}
<dl class="time-table">
<dt class="time-table__destination time-table__destination1">Metsakooli</dt>
<dd class="time-table__time">23:22</dd>
<dd class="time-table__time">23:32</dd>
<dd class="time-table__time">23:42</dd>
<dd class="time-table__time">23:52</dd>
<dd class="time-table__time">00:02</dd>
<dt class="time-table__destination time-table__destination2">Männiku</dt>
<dd class="time-table__time">23:27</dd>
<dd class="time-table__time">23:37</dd>
<dd class="time-table__time">23:47</dd>
<dd class="time-table__time">23:57</dd>
<dd class="time-table__time">00:07</dd>
</dl>
Or without using grid's template areas:
.time-table {
display: grid;
grid-gap: 1em;
grid-template-columns: repeat(4, 1fr);
list-style: none;
padding: 0;
}
.time-table__time {
background-color: #34ace0;
display: block;
color: #fff;
margin: 0;
}
.time-table__destination::before {
content: '\021D2';
display: inline-block;
transform: translateX(-5px);
}
@media (max-width: 35em) {
.time-table {
grid-template-columns: repeat(2, 1fr);
grid-template-areas:
"destination1 destination2"
"time time";
}
.time-table__destination::before {
transform: translateX(-5px);
}
}
<dl class="time-table">
<dt class="time-table__destination time-table__destination1">Metsakooli</dt>
<dd class="time-table__time">23:22</dd>
<dd class="time-table__time">23:32</dd>
<dd class="time-table__time">23:42</dd>
<dd class="time-table__time">23:52</dd>
<dd class="time-table__time">00:02</dd>
<dt class="time-table__destination time-table__destination2">Männiku</dt>
<dd class="time-table__time">23:27</dd>
<dd class="time-table__time">23:37</dd>
<dd class="time-table__time">23:47</dd>
<dd class="time-table__time">23:57</dd>
<dd class="time-table__time">00:07</dd>
</dl>
But as you can see, the first approach fails to render the different times under the appropriate route title. The second approach creates the rows, but doesn't list them in the correct order and fails to hoist the second title (). My questions are:
- How can I make the times (<dd>
) appear under their respective destination/route?
- Is there a more elegant way to have the first row's cells span 2 columns and have the rest of the elements take the place of grid area time
, like using grid-auto-rows
? (I bet there is...)
The problem with the HTML that you've provided is that there's no way of associating the <dd>
elements with a unique <dt>
element, under which the .time-table__time
elements should be aligned.
It is possible, with JavaScript, to take advantage of the order
property to provide that visual identity, but it's an overwrought solution to a problem that can be better solved by changing the HTML.
The problem with using the grid-template-areas
is, as you've found, that you create a named area that spans four columns; and all the <dd>
elements are placed in that one named area.
The revised HTML, below, uses two <dl>
elements, each with its own <dt>
and <dd>
descendants to uniquely associate the two together; those <dl>
elements are themselves wrapped in <li>
elements, themselves the children of an <ol>
element. This is because the HTML you're showing – without context – seems to be an ordered list of destinations.
I was tempted to change the <dl>
elements themselves into <ol>
elements, given that they seem to be ordered lists of times, albeit with a title. However, semantics aside, the following is my suggestion of how you can produce your apparent requirements:
/* Setting the margin and padding of all
elements to zero: */
*,
::before,
::after {
margin: 0;
padding: 0;
}
/* Adjust to taste: */
html,
body {
background-color: #fff;
}
/* Defining a custom CSS Property for
later use: */
:root {
--numParentColumns: 2;
}
/* Removing default list-styling: */
ol,
li,
dl,
dt,
dd {
list-style-type: none;
}
ol {
/* Setting the display type of the <ol> element
to that of 'grid': */
display: grid;
/* Defining the grid columns, using the previously-
defined --numParentColumns variable to supply the
integer to the repeat() function, and setting each
column to the width of 1fr: */
grid-template-columns: repeat(var(--numParentColumns), 1fr);
/* Adjust to taste: */
width: 90vw;
grid-column-gap: 0.5em;
margin: 0 auto;
}
ol>li dl {
/* Setting the <dl> elements' display to 'grid': */
display: grid;
/* Defining the number of grid columns to that value
held in the --numParentColumns variable, retaining
the 1fr width: */
grid-template-columns: repeat(var(--numParentColumns), 1fr);
grid-column-gap: 0.25em;
}
dt.time-table__destination {
/* Rather than using specific named grid-areas
here we place the <dt> elements in column 1
and span 2 columns: */
grid-column: 1 / span 2;
background-color: limegreen;
}
dt.time-table__destination::before {
content: '\021D2';
margin: 0 1em 0 0;
}
dd.time-table__time {
background-color: #34ace0;
}
/* in displays where the width is at, or below,
35em we update some properties: */
@media (max-width: 35em) {
dd.time-table__time {
/* Here we place the <dd> elements in the
first column and have them span 2
columns: */
grid-column: 1 / span 2;
}
}
/* At page-widths less than 15em (not mentioned in
the question): */
@media (max-width: 15em) {
/* We update the --numParentColumns variable to
1, as a tangential demonstration of how useful
CSS custom properties can be: */
:root {
--numParentColumns: 1;
}
}
<ol>
<li>
<dl>
<dt class="time-table__destination time-table__destination1">Metsakooli</dt>
<dd class="time-table__time">23:22</dd>
<dd class="time-table__time">23:32</dd>
<dd class="time-table__time">23:42</dd>
<dd class="time-table__time">23:52</dd>
<dd class="time-table__time">00:02</dd>
</dl>
</li>
<li>
<dl class="time-table">
<dt class="time-table__destination time-table__destination2">Männiku</dt>
<dd class="time-table__time">23:27</dd>
<dd class="time-table__time">23:37</dd>
<dd class="time-table__time">23:47</dd>
<dd class="time-table__time">23:57</dd>
<dd class="time-table__time">00:07</dd>
</dl>
</li>
</ol>
References: