带有响应正方形的网格布局

A grid layout with responsive squares

我想创建一个带有响应式方块的网格布局。

我觉得我应该可以使用 CSS 网格布局来做到这一点,但无法将每个正方形的高度设置为等于宽度。

在每个正方形之间设置间距也有问题。

使用 flexbox 会更好吗?

目前我的 HTML 看起来像这样,但会是动态的,因此可以添加更多方块。当然,它需要响应,因此最好使用媒体查询将其折叠成一列。

<div class="square-container">

  <div class="square">
    <div class="content">
    </div>
  </div>

  <div class="square">
    <div class="content spread">
    </div>
  </div>

  <div class="square">
    <div class="content column">
    </div>
  </div>

</div>

使用css网格,这是我得到的

.square-container{
    display: grid;
    grid-template-columns: 30% 30% 30%;
    .square {

    }
}

我能够更进一步地使用 flexbox 并能够使用 space-between 将正方形与漂亮的排水沟对齐,但仍在努力使高度与每个正方形的宽度相匹配。

我找不到任何使用 flexbox 或 grid 完成此操作的示例,但也将不胜感激。

谢谢

尝试使用视口百分比单位

jsFiddle

.square-container {
  display: grid;
  grid-template-columns: repeat(3, 30vw);
  grid-template-rows: 30vw;
  grid-gap: 2.5vw;
  padding: 2.5vw;
  background-color: gray;
}

.square {
  background-color: lightgreen;
}

body {
  margin: 0; /* remove default margins */
}
<div class="square-container">
  <div class="square">
    <div class="content"></div>
  </div>
  <div class="square">
    <div class="content spread"></div>
  </div>
  <div class="square">
    <div class="content column"></div>
  </div>
</div>

来自规范:

5.1.2. Viewport-percentage lengths: the vw, vh, vmin, vmax units

The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly.

  • vw unit - Equal to 1% of the width of the initial containing block.
  • vh unit - Equal to 1% of the height of the initial containing block.
  • vmin unit - Equal to the smaller of vw or vh.
  • vmax unit - Equal to the larger of vw or vh.

可以利用padding是根据width计算出来的,直接padding-top: 100%设置square 网格项(网格项现在是方形的)。


2019年更新

请注意,对于 flex items 以及 grid items 之前,这并不适用 - 请参阅 post 在评论中链接到这个答案:

Now that there is a consensus between browsers (newer versions) to have the same behaviour for padding for flex items and grid items, you can use this solution.

参见下面的演示:

.square-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
  grid-gap: 10px;
}

.square {
  background: cadetblue;
  padding-top: 100%; /* padding trick directly on the grid item */
  box-sizing: border-box;
  position: relative;
}

.square .content { /* absolutely positioned */
  position: absolute;
  top: 0;
  right:0;
  left: 0;
  bottom: 0;
}
<div class="square-container">
  <div class="square">
    <div class="content"> some content here</div>
  </div>
  <div class="square">
    <div class="content"> some content here</div>
  </div>
  <div class="square">
    <div class="content"> some content here</div>
  </div>
  <div class="square">
    <div class="content"> some content here</div>
  </div>
  <div class="square">
    <div class="content column">some content here and there is a lot of text here</div>
  </div>
  <div class="square">
    <div class="content spread">text</div>
  </div>
  <div class="square">
    <div class="content column">some text here</div>
  </div>
</div>

padding-bottom 技巧是最常用的方法。

您可以将它与 Flexbox 和 CSS Grid 结合使用,并且由于对 margin/padding 使用百分比会导致 flex/grid 项的结果不一致( 在较旧的浏览器版本上, 见下面的编辑注释), 可以添加一个额外的包装器,或者像这里一样,使用伪元素,所以带有百分比的元素不是 flex/grid项目。


编辑: 注意,有一个 ,现在在 flex/grid 项目上使用时应该给出一致的结果。但请注意,旧版本仍然会出现此问题。


请注意,如果您要向 content 元素添加内容,则需要绝对位置以保持正方形的纵横比。

Fiddle demo - Flexbox

编辑 2: 在评论中有人问我如何使文本居中,所以我在下面的代码片段中添加了它。

.square-container {
  display: flex;
  flex-wrap: wrap;
}

.square {
  position: relative;
  flex-basis: calc(33.333% - 10px);
  margin: 5px;
  border: 1px solid;
  box-sizing: border-box;
}

.square::before {
  content: '';
  display: block;
  padding-top: 100%;
}

.square .content {
  position: absolute;
  top: 0; left: 0;
  height: 100%;
  width: 100%;

  display: flex;               /* added for centered text */
  justify-content: center;     /* added for centered text */
  align-items: center;         /* added for centered text */
}
<div class="square-container">

  <div class="square">
    <div class="content">
      <span>Some centered text</span>
    </div>
  </div>

  <div class="square">
    <div class="content spread">
    </div>
  </div>

  <div class="square">
    <div class="content column">
    </div>
  </div>

  <div class="square">
    <div class="content spread">
    </div>
  </div>

  <div class="square">
    <div class="content column">
    </div>
  </div>

</div>


CSS网格版

.square-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
  grid-gap: 10px;
}

.square {
  position: relative;
  border: 1px solid;
  box-sizing: border-box;
}

.square::before {
  content: '';
  display: block;
  padding-top: 100%;
}

.square .content {
  position: absolute;
  top: 0; left: 0;
  height: 100%;
  width: 100%;
}
<div class="square-container">

  <div class="square">
    <div class="content">
    </div>
  </div>

  <div class="square">
    <div class="content spread">
    </div>
  </div>

  <div class="square">
    <div class="content column">
    </div>
  </div>

  <div class="square">
    <div class="content spread">
    </div>
  </div>

  <div class="square">
    <div class="content column">
    </div>
  </div>

</div>

几天来,我很惊讶在 2020 年没有简单的解决方案。我确信使用 CSS 网格这将是小菜一碟...... Ason 提供的 Flexbox 解决方案是唯一可以跨浏览器工作的解决方案。在 Stack 上,我发现了另一种使用 CSS 网格的解决方案,它使用 padding-bottom: 100% 但它在 Firefox 中不起作用(页脚下方有很多白色 space)。

这是我对这个问题的看法,我认为这是我这些天遇到的所有问题中最简单的解决方案。

CSS Codepen 上的网格解决方案: https://codepen.io/abudimir/pen/ExKqyGp

<div class="square-container">

您可以使用 CSS aspect-ratio 属性.

在所有现代浏览器中实现此目的

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 5px;
}

.container div {
  aspect-ratio: 1 / 1;
  
  /* Styles below just for demo */
  background-color: orange;
  color: white;
  font-family: Arial;
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class="container">
  <div>A</div>
  <div>B</div>
  <div>C</div>
  <div>D</div>
  <div>E</div>
  <div>F</div>
  <div>G</div>
</div>