【问题标题】:Reorder row columns in repeating CSS grid/table在重复的 CSS 网格/表格中重新排序行列
【发布时间】:2023-03-10 15:12:01
【问题描述】:

当以表格/网格的方式显示多个项目时,CSS 是否可以在不知道“行”数的情况下覆盖元素顺序?

例如这是一个标准表,也是相同数据的更紧凑的替代方案。但是我必须为第二个(1、4、2、3)移动一些 HTML 元素,否则第 4 列会偏移一行。

.layout1 {
  margin: 1em 0;
  width: 400px;
  display: grid;
  grid-template-columns: auto auto auto max-content;
  grid-row-gap: 0.2em;
}
.layout2 {
  margin: 1em 0;
  width: 200px;
  display: grid;
  grid-template-columns: auto auto max-content;
}
.layout2 .col1 {
  margin-top: 0.2em;
  grid-column: span 2;
}
.layout2 .col4 {
  margin-top: 0.2em;
  grid-row: span 2;
}
.layout2-5 .col2 {
  grid-column: 1;
}
.layout2-5 .col3 {
  grid-column: 2;
}
.layout2-5 .col4 {
  grid-column: 3;
}
.col1, .col2, .col3, .col4 { padding: 0 1em; }
.col1 { background: #F99; }
.col2 { background: #9F9; }
.col3 { background: #99F; }
.col4 { background: #9FF; }
<div class="layout1">
  <!--"row"-->
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
  <!--"row"-->
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
</div>
<div class="layout2">
  <!--"row"-->
  <div class="col1">1</div><div class="col4">4</div><div class="col2">2</div><div class="col3">3</div>
  <!--"row"-->
  <div class="col1">1</div><div class="col4">4</div><div class="col2">2</div><div class="col3">3</div>
  <div class="col1">1</div><div class="col4">4</div><div class="col2">2</div><div class="col3">3</div>
</div>
 <div class="layout2 layout2-5">
  <!--"row"-->
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
  <!--"row"-->
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
  <div class="col1">1</div><div class="col2">2</div><div class="col3">3</div><div class="col4">4</div>
</div>

【问题讨论】:

  • 据我所知,只有在使用 Flexbox 时,才能在 CSS 中重新排序行
  • 如果我可以使用flex 或普通table 或其他任何可以做到这一点。但是,如果您指的是order 属性,那么它也适用于网格,但是您将如何将其应用于此?

标签: html css css-tables css-grid


【解决方案1】:

解决方案是使用grid-auto-flow: dense,允许填充以前的单元格,只要数据项填满所有单元格,布局完全可重复。

.layout2 {
  margin: 1em 0;
  width: 200px;
  display: grid;
  grid-template-columns: auto auto max-content;
  grid-auto-flow: dense;
}
.layout2 .col1 {
  grid-column: span 2;
}
.layout2 .col2 {
  grid-column: 1;
}
.layout2 .col3 {
  grid-column: 2;
}
.layout2 .col4 {
  grid-column: 3;
  grid-row: span 2;
  height: 2.5em;
}
.col1, .col2, .col3, .col4 { padding: 0 1em; }
.col1 { background: #F99; }
.col2 { background: #9F9; }
.col3 { background: #99F; }
.col4 { background: #9FF; }
<div class="layout2">
  <!--"row"-->
  <div class="col1">1</div>
  <div class="col2">2</div>
  <div class="col3">3</div>
  <div class="col4">4</div>

  <div class="col1">1</div>
  <div class="col2">2</div>
  <div class="col3">3</div>
  <div class="col4">4</div>
</div>

逐步使用grid-auto-flow: row(默认)

使用带有grid-template-columns: auto auto max-content 的网格并从具有“光标”在 (1,1) 处的空网格开始,一次添加一个元素。

第一个元素有 grid-column: span 2;,因此它进入 (1,1) 和 (2,1),“光标”现在位于 (3,1)。

然而,下一个元素有grid-column: 1,但网格当前位于 (3,1),因此它跳过 (3,1) 并转到 (1,2) 的下一行) 然后前进到 (2,2)。

下一个元素有grid-column: 2,它与网格已经到达的位置相匹配,因此元素进入(2,2)并且网格移动到(3,1)。

接下来的第四个元素有grid-column: 3 和grid-row: span 2。那匹配并且下面的单元格是空的,所以它占用(3,2)和(3,3)。然而,这会在 (1,1) 处留下一个间隙,因为跨度总是“向前”。

现在开始下一个数据项,与grid-column: 1 和 (2, 3) 匹配的 (1,3) 处的网格仍然是空的,所以元素会出现在那里。

(3,3) 已被采用,因此被跳过,但这没关系,因为下一个元素无论如何都是第 1 列,然后是第 2 列,然后返回到第 4 列,它再次跨越下方,尽管这次有无论如何,上面已经有了。

与grid-auto-flow: dense

使用密集值,网格将尝试填充任何间隙,例如 (3,1) 处的间隙。这使得前 3 个元素的布局相同(由于列限制),但是当第 4 个元素想要迄今为止为空的第 3 列时,网格布局将其移动到该列的顶部,这次不留空隙。并且没有任何间隙,下一组元素重复此操作。

所以一般的解决方案

  • 为了可重复,每个数据项/“行”必须具有填充所有单元格的元素,以便每个新单元格都以新行开头。
  • 为了允许元素填充“已通过”的单元格,请使用grid-auto-flow: dense,否则网格元素需要与视觉上的顺序相同。
  • order 属性并没有太大帮助,因为您不能让它每隔 n 项重复一次。您需要将 CSS 规则设置为元素总数(对于动态列表/数据集不实用),或者可能使用内联 style 属性。
  • 将grid-row 设置为显式行号也有同样的问题。

可以使用密集的任何排序:

否则元素需要按顺序排列,否则单元格会被跳过,而它只会“向前”前进:

【讨论】:

    【解决方案2】:

    您想要实现的目标不可能是 grid 显示。在不使用行的情况下重新排序列的唯一可能方法是使用flexbox。使用 flex-direction: row-reverse 自动 将行从最后到第一重新排序,您甚至可以使用 flex-wrap: wrap-reverse 跨行“溢出”这种反转>.

    还可以完全修改元素出现的顺序,方法是使用order 属性对其进行扩展。在以下示例中,我已将其添加到几个 :nth-of-type(4n) pseduo-selector。请注意,它特别是 4n,因为每个“行”有四列。

    .flex {
      width: 342px;
      display: flex;
      flex-direction: row-reverse;
      flex-wrap: wrap-reverse;
    }
    
    .flex > div:nth-of-type(4n) {
      order: 2;
    }
    
    .flex > div:nth-of-type(4n + 1) {
      order: 1;
    }
    
    .flex > div:nth-of-type(4n + 2) {
      order: 3;
    }
    
    .flex > div:nth-of-type(4n + 3) {
      order: 4;
    }
    
    .col1, .col2, .col3, .col4 {
      width: 50px;
      padding: 1em;
      margin: 0.1em;
      text-align: center;
    }
    
    .col1 {
      background: #F99;
    }
    
    .col2 {
      background: #9F9;
    }
    
    .col3 {
      background: #99F;
    }
    
    .col4 {
      background: #9FF;
    }
    <div class="flex">
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
    </div>

    在上面的示例中,首先包装所有.col3 元素,然后是所有.col2 元素,然后是所有.col4 元素,然后是所有.col1 元素。随意调整它以适应;您需要做的就是更改order 的值,以及应用order 属性的元素。请记住,order 可以达到 total 元素的数量;如果您愿意,您可以手动指定 所有 12 个 位置:

    .flex {
      width: 342px;
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
    }
    
    .flex > div:nth-of-type(1) {
      order: 4;
    }
    
    .flex > div:nth-of-type(2) {
      order: 2;
    }
    
    .flex > div:nth-of-type(3) {
      order: 1;
    }
    
    .flex > div:nth-of-type(4) {
      order: 3;
    }
    
    .flex > div:nth-of-type(5) {
      order: 8;
    }
    
    .flex > div:nth-of-type(6) {
      order: 6;
    }
    
    .flex > div:nth-of-type(7) {
      order: 5;
    }
    
    .flex > div:nth-of-type(8) {
      order: 7;
    }
    
    .flex > div:nth-of-type(9) {
      order: 12;
    }
    
    .flex > div:nth-of-type(10) {
      order: 10;
    }
    
    .flex > div:nth-of-type(11) {
      order: 9;
    }
    
    .flex > div:nth-of-type(12) {
      order: 11;
    }
    
    .col1, .col2, .col3, .col4 {
      width: 50px;
      padding: 1em;
      margin: 0.1em;
      text-align: center;
    }
    
    .col1 {
      background: #F99;
    }
    
    .col2 {
      background: #9F9;
    }
    
    .col3 {
      background: #99F;
    }
    
    .col4 {
      background: #9FF;
    }
    <div class="flex">
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
      <!--"row"-->
      <div class="col1">1</div>
      <div class="col2">2</div>
      <div class="col3">3</div>
      <div class="col4">4</div>
      
    </div>

    希望这会有所帮助! :)

    【讨论】:

    • 不太确定你想展示什么。您将所有相同的类放在组中,3,3,3,2,2,2,4,4,4,1,1,1 而不是像 3,2,4,1,3,2,4, 1等? order 属性可以与网格一起使用,如果这是您所显示的?请参阅drafts.csswg.org/css-grid/#order-property“order 属性也适用于网格项。它会影响它们的自动放置和绘制顺序。”
    • 可以使用上述方法将项目重新排列成您想要的任何顺序。如果您愿意,您可以轻松地在每一行显示它,如 3, 2, 4, 1,通过为 each 元素指定一个 order,最多为元素总数(请参阅我的最后一段)。这就是你想要达到的目标吗?如果不是,您究竟要达到什么目标,以及究竟是什么?另外,您的限制是什么?
    • 我已更新我的答案以展示第二个示例,所有三行都使用3, 2, 4, 1 进行订单。
    • 好吧,我仍然想要理想的行跨度。但使用原始 HTML。无论如何,我想我发现通过所有属性的规范,一个适用于我能想到的所有情况的解决方案。例如这里的订单和你做的一样,但我不需要nth-of-type 的所有东西,它只是重复。 codepen.io/anon/pen/GvOOZW
    猜你喜欢
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多