CSS 网格:通用行列 CSS 抽象特定列和行计数的规则

CSS Grid: Universal row column CSS rules which abstract away specific column and row counts

我想利用 CSS 网格 来均匀调整属于同一 CSS 网格轴 :

[class*=' container-grid-'], [class^='container-grid-'] {
  /* give margin-bottom to all kinds of "container-grid-", see  */
  margin-bottom: 2rem;
}

[class*=' container-grid-']  > .col, [class^='container-grid-'] > .col {
  display: contents;
}

.container-grid-2by2 {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, auto);
  row-gap: 0;
  column-gap: 1rem;
}


.container-grid-3by3 {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, auto);
  row-gap: 0;
  column-gap: 1rem;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
 background-color: skyblue;
}

.limit-width {
  max-width: 20rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid-2by2</code></h1>

<div class="container-grid-2by2">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid-3by3</code></h1>

<div class="container-grid-3by3">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz3
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 
    </div>
    <div class="blue">
      Baz3
    </div>
  </div>
</div>

</div>

如您所见,位于同一 CSS 网格行轴 上的元素具有相同的高度,例如文本内容很少的单元格 (Foo1) 会拉伸以匹配文本内容最多的单元格的高度 (Foo2 Foo2 Foo2 ...)。太棒了,这正是我想要的!

HTML 遵循以下结构:<div class="container-grid-*"> 元素充当 CSS 网格容器;里面有几个 <div class="col"> 作为列;然后在这些列中的实际内容 HTML 元素。 .col 元素使用 display: contents;CSS grid cell 决定“委托”给实际内容 HTML 元素。

但是现在,我的 CSS 需要对每一列和每一行计数的明确规则:.container-grid-2by2.container-grid-3by3.container-grid-2by3.container-grid-3by2 等.

应该有办法重构它,不是吗?

是否有任何 CSS 技巧可以自动导出 CSS 网格列数和行数?

就我的情况而言,始终可以假设在一个容器内,每一列都具有相同数量的实际 HTML 内容元素;例如在容器内,所有列都将包含 x 个元素。

我找到了两个解决方案,它们还没有完全通用化,并且依赖于解决方法和技巧。

Not-so-hacky解法

已在 Chrome 96 和 Firefox 94 中成功测试。

此解决方案依赖于一组“pre-calculated”CSS 规则,将 nth-child(x) .col child 放入 x 的 grid-row。由于 .container-grid 定义了一个完全隐式(相对于显式)CSS 网格,下一个 .col 的第一个元素将自动引入下一列并放置在下一列中。

.container-grid {
  display: grid;
  row-gap: 0;
  column-gap: 1rem;
  grid-auto-columns: 1fr;
}

.container-grid > .col {
  display: contents;
}


.container-grid > .col > div:nth-child(1) {
  grid-row: 1;
}

.container-grid > .col > div:nth-child(2) {
  grid-row: 2;
}

.container-grid > .col > div:nth-child(3) {
  grid-row: 3;
}

.container-grid > .col > div:nth-child(4) {
  grid-row: 4;
}

/* ... and so on up to the maximum amount of vertical grid elements you can imagine in each row */

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: skyblue;
}

.yellow {
  background-color: yellow;
}

.limit-width {
  max-width: 30rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid</code> 1col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 1col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 3col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 3col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 4row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
    <div class="yellow">
      Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
    <div class="yellow">
      Qux2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
    <div class="yellow">
      Qux3 Qux3 Qux3 Qux3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
    <div class="yellow">
      Qux4
    </div>
  </div>
</div>

</div>

非常骇人听闻的解决方案

已在 Chrome 96 和 Firefox 94 中成功测试。

此解决方案依赖于每个 .col::after pseudo-element:此 pseudo-element occupies/hacks 足够多 grid-row 溢出到下一个隐式列。 grid-auto-columns: 1fr 0; 中的 0 确保这个虚列不占据水平 space.

此解决方案依赖于

.container-grid {
  display: grid;
  row-gap: 0;
  column-gap: 0.5rem; /* column-gap is created for both .col and pseudo-element phantom column, therefore to achieve an effective column-gap of 1rem, we use the half value of 0.5rem */
  grid-auto-flow: column;
  grid-auto-columns: 1fr 0; /* 1fr is for each .col, 0 is for its follow-up pseudo-element phantom column to occupy no horizontal space */ 
}

.container-grid > .col {
  display: contents;
}

.container-grid > .col::after {
  content: "";
  grid-row: span 8; /* span x, where x is the maximum amount of elements that will every be in a column */
  background-color: pink;
}

.container-grid > .col:only-child::after {
  /* ugly fix for the case of 1col x 1row and 1col x 2row */
  grid-row: 9; /* y, where y = x + 1, where x is the maximum amount of elements that will every be in a column */
}

.container-grid > .col:not(:first-child):last-child::after {
  /* last .col shall not create a follow-up pseudo-element phantom column
  content: unset; 
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: skyblue;
}

.yellow {
  background-color: yellow;
}

.limit-width {
  max-width: 30rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid</code> 1col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 1col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 3col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 3col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 4row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
    <div class="yellow">
      Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
    <div class="yellow">
      Qux2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
    <div class="yellow">
      Qux3 Qux3 Qux3 Qux3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
    <div class="yellow">
      Qux4
    </div>
  </div>
</div>

</div>

更新:看起来这个非常骇人听闻的解决方案无法通过 运行 代码片段,但它在代码片段 Editor.

中有效