使用自动布局将 CSS 网格包裹起来

6

我正在尝试构建一个包含卡片式项目的网格。每种类型的单元格(标题、图像、文本、按钮等)在每行中应具有相等的高度,由最大单元格的内容确定,就像下面的代码段一样。

现在我正在尝试限制列数,并让卡片换行,就像在基于弹性盒子的解决方案中使用flex-wrap: wrap;一样。列数应通过媒体查询确定。这是否可以在没有使用尚未支持的子网格的情况下实现?

此外,使用子网格的解决方案会是什么样子?我猜它将在当前浏览器中降级为具有不等高度的单元格?

.grid {
  display: grid;
  grid-template-rows: repeat(4, auto);
  grid-gap: 10px;
  grid-auto-flow: column;
  grid-auto-columns: auto;
}
<div class="grid">

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">text
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 2 is longer and may span multiple lines</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est.
  </p>
  <button class="d">Button</button>


  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget.
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget. Suspendisse pulvinar arcu massa, quis
    varius velit facilisis tincidunt. Proin sed cursus orci.
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </p>
  <button class="d">Button</button>
</div>


您需要将每张卡片分别包装在一个单独的 div 中... 这是正常的方法。没有 CSS 方法可以使行或元素之间的高度相等,它们不共享父元素。 - Paulie_D
2个回答

1
你现在已经有一个解决方案了,虽然浏览器支持不是很理想,但它确实能够工作,即display: content。你需要将元素包裹在一个辅助div中,我将其设置为类card。然后,使用display: content使卡片从布局中消失。

.grid {
  display: grid;
  grid-gap: 10px;
  grid-auto-columns: 1fr;
  grid-auto-flow: dense;
}

.card {
  display: contents;
}

.card:nth-child(odd) * {
  grid-column-start: 1;
}

.card:nth-child(even) * {
  grid-column-start: 2;
}

@media screen and ( min-width: 1300px) {
  .card:nth-child(3n + 0) * {
    grid-column-start: 3;
  }
  .card:nth-child(3n + 1) * {
    grid-column-start: 1;
  }
  .card:nth-child(3n + 2) * {
    grid-column-start: 2;
  }
}
<div class="grid">

  <div class="card">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100">
    <p class="c">text
    </p>
    <button class="d">Button</button>
  </div>

  <div class="card">
    <h2 class="a">Header 2 is longer and may span multiple lines</h2>
    <img class="b" src="https://placekitten.com/400/100">
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="card">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100">
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="card">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100">
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget. Suspendisse pulvinar arcu massa, quis
      varius velit facilisis tincidunt. Proin sed cursus orci.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="card">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100">
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </p>
    <button class="d">Button</button>
  </div>
</div>

我错过了最简单的解决方案:

由于您已经拥有一个扁平的HTML,并且打算使用媒体查询,因此您可以在扁平的HTML上使用相同的思路(nth-选择器)。

.grid {
  display: grid;
  grid-gap: 10px;
  grid-auto-flow: dense;
  grid-auto-rows: 1fr;
}

.card {
  display: contents;
}

h2,
img,
p,
button {
  grid-column-start: 1;
}

h2:nth-of-type(even),
img:nth-of-type(even),
p:nth-of-type(even),
button:nth-of-type(even) {
  grid-column-start: 2;
}

@media screen and ( min-width: 1300px) {

h2:nth-of-type(3n + 1),
img:nth-of-type(3n + 1),
p:nth-of-type(3n + 1),
button:nth-of-type(3n + 1) {
  grid-column-start: 1;
}
h2:nth-of-type(3n + 2),
img:nth-of-type(3n + 2),
p:nth-of-type(3n + 2),
button:nth-of-type(3n + 2) {
  grid-column-start: 2;
}
h2:nth-of-type(3n),
img:nth-of-type(3n),
p:nth-of-type(3n),
button:nth-of-type(3n) {
  grid-column-start: 3;
}

}
<div class="grid">

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">text
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 2 is longer and may span multiple lines</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est.
  </p>
  <button class="d">Button</button>


  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget.
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget. Suspendisse pulvinar arcu massa, quis
    varius velit facilisis tincidunt. Proin sed cursus orci.
  </p>
  <button class="d">Button</button>

  <h2 class="a">Header 1</h2>
  <img class="b" src="https://placekitten.com/400/100" />
  <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </p>
  <button class="d">Button</button>
</div>


有没有办法避免滚动条,并在没有足够空间时自动换行? - Temani Afif
@TemaniAfif 这只是设置媒体查询在正确的断点上的问题。我已经编辑了答案,以此来做到这一点(对于我已经拥有的媒体查询,为较小的屏幕添加另一个查询非常容易)。我还添加了另一个更好的支持答案。 - vals

1
这是一个需要使用子网格的好例子——在像这个问题中的布局中,对齐网格表格是至关重要的。
在浏览器实现子网格的建议级别2规范之前,我们只能将每一列包装在一个元素中,然后再使用外部网格容器进行包装。
下面是来自CSS Grid Layout Module Level 2的{{编辑草案}}摘录:

2. 子网格

一个网格项本身可以通过给它display: grid;使其成为网格容器,在这种情况下,它的内容布局将独立于它参与的网格的布局。

在某些情况下,多个网格项的内容需要对齐。一个本身是网格项的网格容器可以将其行和列的定义推迟到其父网格容器中,使其成为子网格。在这种情况下,子网格的网格项参与调整父网格容器的网格大小,从而使两个网格的内容对齐。

这篇文章here讨论了这个问题。

下面是一个使用嵌套网格容器(子网格可以看起来像这样,但不会破坏“非等亲属规则”)的模拟 - 参见下面的演示:

.wrapper {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
}

.grid {
  display: grid;
  grid-template-rows: repeat(4, 1fr);
  justify-items: flex-start;
  border: 1px solid #07c;
}

img {
  width: 100%;
}

button {
  align-self: center;
  justify-self: center;
}

p {
  padding: 0 10px;
}
<div class="wrapper">

  <div class="grid">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100" />
    <p class="c">text
    </p>
    <button class="d">Button</button>
  </div>

  <div class="grid">
    <h2 class="a">Header 2 is longer and may span multiple lines</h2>
    <img class="b" src="https://placekitten.com/400/100" />
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="grid">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100" />
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="grid">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100" />
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis et cursus ligula. Maecenas non pharetra dui, eu tincidunt mi. Vivamus vitae luctus risus. Etiam vehicula sem est, non ultricies lectus placerat eget. Suspendisse pulvinar arcu massa, quis
      varius velit facilisis tincidunt. Proin sed cursus orci.
    </p>
    <button class="d">Button</button>
  </div>

  <div class="grid">
    <h2 class="a">Header 1</h2>
    <img class="b" src="https://placekitten.com/400/100" />
    <p class="c">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </p>
    <button class="d">Button</button>
  </div>

</div>

一种可能的定义可以是:

.wrapper {
  display: grid; /* outer grid */
  /* sets a wrapping grid container with items of width around 400px */
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); 
}

.grid {
  grid-row: span 4; /* span 4 rows */
  display: grid;
  /* magic is here */
  grid-template-rows: subgrid; /* create a sub-grid with the 4 parent grid rows */
}

谢谢,你的模拟对于几乎等高元素的情况很有效。但是我的用例比较复杂。我有一个关于子网格定义的问题:据我所知,子网格“占用”其父级网格中的位置。通过在子网格中使用 grid-row: span 4,是否会在父级中隐式创建网格行? - sk1p

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接