重新排列重复的行列 CSS grid/table

Reorder row columns in repeating CSS grid/table

当以 table/grid 方式显示多个项目时,CSS 是否可以在事先不知道 "rows" 的数量的情况下覆盖元素顺序?

例如这是一个标准的 table,并且是相同数据的更紧凑的替代方案。但是我必须为第二个(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>

grid 显示器不可能实现您想要实现的目标。在不使用行的情况下对列重新排序的唯一可能方法是利用 flexbox. Using flex-direction: row-reverse automatically re-orders the rows from last to first, and you can even 'overflow' this reversal across rows with flex-wrap: wrap-reverse.

也可以 完全 修改元素出现的顺序,方法是使用 order property. In the following example, I've added it to a few :nth-of-type(4n) 伪选择器对其进行扩展。请注意,它特别是 4n 因为每个 'row'.

有四列

.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 可以达到 总数 个元素;如果需要,您可以手动指定 所有 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>

希望对您有所帮助! :)

解决方案是使用 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 的网格,并从 "cursor" 在 (1,1) 处的空网格开始,一次添加一个元素。

第一个元素有 grid-column: span 2;,所以它进入 (1,1) 和 (2,1),现在 "cursor" 在 (3,1)。

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

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

接下来第 4 个元素有 grid-column: 3grid-row: span 2。匹配并且下面的单元格是空的,所以它占据了 (3,2) 和 (3,3)。但是,这在 (1,1) 处留下了一个空隙,因为跨度总是 "forward".

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

(3,3) 已经被采用,所以被跳过了,但这没关系,因为下一个元素无论如何都是第 1 列,然后是第 2 列,然后回到第 4 列,它再次向下跨越,虽然这次反正上面已经有东西了

grid-auto-flow: dense

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

所以通用解决方案

  • 为了可重复,每个数据项/"row",必须有元素来填充所有单元格,这样每个新的单元格都从新的行开始。
  • 为了允许元素填充单元格 "already passed",请使用 grid-auto-flow: dense,否则网格元素的顺序需要与它们在视觉上的顺序相同。
  • order 属性 并没有多大帮助,因为你不能让它重复每 n 个项目。您需要根据元素总数制定 CSS 规则(对于动态 list/data 集不实用)或者可能使用内联 style 属性。
  • grid-row 设置为明确的行号也有同样的问题。

密集可以使用任何顺序:

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