如何让较小的项目自己设置行?

How to make smaller items setting rows themselves?

我正在尝试创建 CSS class 允许我在数据库中存储小部件的网格布局配置并且是动态的。

我的目标是拥有可重复使用的 classes 以根据 HTML 中的顺序和 class 定义的大小自动定位小部件。问题是小部件需要有定义的行值才能正确放置。

我的目标是实现如下布局:

我创建了以下 HTML 和 CSS:

<div class="widgets-grid">
  <div class="widgets-grid__widget widget--medium">1</div>
  <div class="widgets-grid__widget widget--small">2</div>
  <div class="widgets-grid__widget widget--small">3</div>
  <div class="widgets-grid__widget">4</div>
  <div class="widgets-grid__widget">5</div>
  <div class="widgets-grid__widget">6</div>
  <div class="widgets-grid__widget">7</div>
</div>
.widgets-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: auto;
  column-gap: 17px;
  row-gap: 15px;

  max-width: 100%;
  padding: 15px;

  .widgets-grid__widget {
    border-radius: 3px;
    box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.15);
    height: 200px;
    background-color: #ffffff;
    grid-column: span 4;
    grid-row: span 2;
  }

  .widgets-grid__widget:nth-child(odd) {
    grid-column: 1 / 3; // left column
  }

  .widgets-grid__widget:nth-child(even) {
    grid-column: 3 / 5; // right column
  }

  .widgets-grid__widget.widget--small {
    grid-column: 2 / 3;
    height: auto;

    // my hack
    &:nth-child(odd) {
      grid-row: 1; // manual positon :(
    }
    &:nth-child(even) {
      grid-row: 2; // manual positon :(
    }
  }

  .widgets-grid__widget.widget--medium {
    grid-column: 1 / 2;
  }
}

因此,如果没有额外的 class 提供的小部件将具有标准尺寸 2x2。还有 2 种其他尺寸:.widget--medium(1 列和 2 行)和 .widget--small(1 行和 1 列)。

我创建了一个 hack 来实现我的目标,但是如果我在第 2 行和第 3 行有小部件,它就不会工作...

// my hack
&:nth-child(odd) {
  grid-row: 1; // manual position :(
}
&:nth-child(even) {
  grid-row: 2; // manual position :(
}

我也试过 grid-row: auto 但是小部件 4 坏了。

请指教!

在 StackBlitz 上试用:https://stackblitz.com/edit/web-platform-5o8cxz

一种解决方案是使用 grid-areas 准确定义您希望元素在网格中的位置,并为每个 class 分配适当的 grid-area。请参阅 grid-areas 文档 here

像这样:

.parent {
  height: 500px;
  width: 800px;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3,  1fr);
  grid-template-areas: "one two four" "one two five" "three two six";
}

.parent > * {
  background-color: gray;
  height: 100%;
  width: 100%;
}

.c1 {
  grid-area: one;
}

.c2 {
  grid-area: two;
}

.c3 {
  grid-area: three;
 }

.c4 {
  grid-area: four;
  
 }

.c5 {
  grid-area: five;
 }

.c6 {
  grid-area: six;
 }
<div class="parent">
   <div class='c1'></div>
   <div class='c2'></div>
   <div class='c3'></div>
   <div class='c4'></div>
   <div class='c5'></div>
   <div class='c6'></div>
</div>

对于您的具体情况,网格试图使所有元素保持文档顺序,因此它正在创建新行以容纳额外的 space 需要。

这是网格的默认行为,但您可以通过将父级 grid-container 设置为具有以下 属性:

来覆盖它
grid-auto-flow: dense

这将允许网格项显示在第一个可用的开放网格中,并且如果您的布局需要,将允许它们不按文档顺序排列。

Grid flow docs

一位非常出色的 YouTube 内容创建者 Kevin Powell 可以教您所有非常方便但鲜为人知的 flex 和 grid 属性。强烈推荐给任何想在网页布局方面做得更好的人:

Masonry Layout