CSS 具有 2 个列标题的网格 4 列布局 <dl>

CSS Grid 4 column layout with 2 column titles for <dl>

给定一个标记:

dl
  dt
  dd
  dd
  ..

  dt
  dd
  dd
  ...

我正在尝试使用 CSS 网格实现以下布局:

  dt      dt
dd  dd  dd  dd
dd  dd  dd  dd
dd  dd  dd  dd
dd  dd  dd  dd

我目前的做法是:

.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: '1D2';
    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>

或者不使用网格的模板区域:

.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: '1D2';
    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>

但是如您所见,第一种方法无法在适当的路线标题下呈现不同的时间。第二种方法创建了行,但没有以正确的顺序列出它们并且无法提升第二个标题 ()。我的问题是: - 如何让时间 (<dd>) 出现在它们各自的 destination/route 下? - 是否有更优雅的方法让第一行的单元格跨越 2 列,并让其余元素代替网格区域 time,例如使用 grid-auto-rows? (我打赌有...)

您提供的 HTML 的问题是无法将 <dd> 元素与唯一的 <dt> 元素相关联,.time-table__time 元素应该对齐。

使用 JavaScript 可以利用 order 属性 来提供视觉标识,但这是对可以更好地解决的问题的过度解决方案通过更改 HTML.

正如您所发现的,使用 grid-template-areas 的问题在于您创建了一个跨越四列的命名区域;并且所有 <dd> 元素都放在那个命名区域中。

修改后的 HTML 下面使用两个 <dl> 元素,每个元素都有自己的 <dt><dd> 后代,以将两者唯一地关联在一起;那些 <dl> 元素本身包裹在 <li> 元素中,它们本身是 <ol> 元素的 children。这是因为您显示的 HTML – 没有上下文 – 似乎 是一个有序的目的​​地列表。

我很想将 <dl> 元素本身更改为 <ol> 元素,因为它们似乎是有序的时间列表,尽管有标题。然而,撇开语义不谈,以下是我对如何产生明显需求的建议:

/* 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: '1D2';
  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>

参考文献:

@DavidThomas 的 answer 帮了我很多,但我最终走向了一个不同的方向。我发现伪元素被认为是网格单元!这为使用 aria 标签作为 <ol> 标题提供了一个很好的机会,我想要的结果如下所示:

.time-table {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-gap: 3em;
    text-align: center;
    color: #fff;
  }

  .time-table__listing {
    display: grid;
    grid-gap: 1em;
    grid-template-columns: repeat(2, 1fr);
    list-style: none;
    --listing-background: #34ace0;
  }
  .time-table__listing:last-child {
    --listing-background: #B33771;
  }
  
  .time-table__listing::before {
    content: '1D2 ' attr(aria-label);
    font-size: 1.2em;
    grid-column: 1 / span 2;
  }
  .time-table__listing:first-child::before {
    background-color: #34ace0;
  }
  .time-table__listing:last-child::before {
    background-color: #B33771;
  }
  .time-table__time {
    background-color: var(--listing-background);
  }
<div class="time-table">
  <ol aria-label="Metsakooli" class="time-table__listing">
    <li class="time-table__time bg-bright-three">23:22</li>
    <li class="time-table__time bg-bright-three">23:32</li>
    <li class="time-table__time bg-bright-three">23:42</li>
    <li class="time-table__time bg-bright-three">23:52</li>
    <li class="time-table__time bg-bright-three">00:02</li>
  </ol>

  <ol aria-label="Männiku" class="time-table__listing">
    <li class="time-table__time bg-bright-three">23:27</li>
    <li class="time-table__time bg-bright-three">23:37</li>
    <li class="time-table__time bg-bright-three">23:47</li>
    <li class="time-table__time bg-bright-three">23:57</li>
    <li class="time-table__time bg-bright-three">00:07</li>
  </ol>
</div>