CSS网格方格布局

37

我想创建一个由方块组成的网格/布局,每行四个方块。方块在屏幕调整大小时不能变形。宽度和高度必须始终相同(我不想使用固定值)。我必须使用CSS网格。有人能帮帮我吗?

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-gap: 5px;
}
.container div {
  background-color: red;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>


1
如果你只想要一个正方形,只需将 padding-bottom: 100%; 添加到 div 中,以防没有内容。 - Temani Afif
@TemaniAfif 如果我里面有一些内容怎么办? - Minio
我已经编辑了我的答案,使其更加通用。 - Temani Afif
4个回答

91

只使用CSS,您可以使用一个伪元素来始终保持宽高比为1:1,或使用新的aspect-ratio属性,例如:

使用CSS可以通过伪元素或使用新的aspect-ratio属性,实现始终保持宽高比为1:1

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-gap: 5px;
}
.container div {
  background-color: red;
  aspect-ratio: 1;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>


2
为什么要使用inline-block而不是block? - Temani Afif
2
好奇一下,在这种情况下,vertical-align有什么用途? - guitarzero
2
@guitarzero 避免默认设置为基线时底部出现4像素间隙。 - Fabrizio Calderan
1
为什么不直接为.container div设置padding-bottom: 100%height: 0,而不使用任何伪元素呢? - Vadim Ovchinnikov
aspect-ratio 轻松解决了我的类似问题,谢谢! - Stabledog
显示剩余2条评论

8
为了探究和满足对于 grid 行为的趣味和好奇,避免使用伪元素,您也可以将高度设置为网格容器的宽度,这样网格系统会自动拉伸行。
一个好的提醒是:请注意https://css-tricks.com/snippets/css/complete-guide-grid/ 和示例https://gridbyexample.com/
如果您的网格占用整个浏览器的宽度,则可以查看以下工作示例。

  * {
  margin: 0;
  padding: 0;
}

.container {
  display: grid;
  height: calc(50vw - 5px);  /*instead playing around with grid gap gap */
  grid-template-columns: 1fr 1fr 1fr 1fr;
}

.container div {
  /* bg to show i'm squarred or not ? */
  background-image: linear-gradient( 45deg, transparent 50%, rgba(0, 0, 0, 0.5) 50%);
 
 margin: 0 5px 5px 0;  /*instead playing around with grid gap gap */
  background-color: red;
}


/* extra for demo, not needed */

.container {
  counter-reset: test;
}

.container div {
  display: flex;  /* or grid */
}

.container div:before {
  counter-increment: test;
  content: 'Div N°:'counter(test)' -';
  margin: auto;/* center me */
  color: yellow;
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

一个CodePen页面,可供修改或测试


1
值得注意的是,如果我们考虑2行,您的高度技巧将起作用,但它应根据行数进行调整。 - Temani Afif
@TemaniAfif,然后将高度设置为children。请注意,50vw(父级上的2行)会降至25vw以适应children ;) - G-Cyrillus
一个小问题是,vw 包括滚动条,所以当有滚动条时,你不会得到完美的正方形。 - Temani Afif
如果您不知道容器的宽度,这也行不通。 - Carlos López Marí

8

另一个技巧是您可以在不破坏比例的情况下放置任何内容。思路是将网格放置在一个大正方形中,然后将其分成小正方形:

.container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: repeat(4,minmax(0,1fr));
  grid-template-rows: repeat(4,minmax(0,1fr));
  grid-gap: 5px;
}

.container div {
  background-color: red;
}

body:before {
  content: "";
  display: block;
  padding-top: 100%;
}

body {
  position: relative;
  margin: 0;
}

img {
  max-width: 100%;
  max-height: 100%;
}
<div class="container">
  <div>any contet here</div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/300?image=1069"></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
  <div>any contet here any contet here</div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
  <div></div>
</div>

您可以控制行数的限制。在上面的例子中,我将它们设置为4行,如果将内边距调整为50%而不是100%,我们只能设置为2行。这样我们会有一个大矩形,其中包含8个方块(每行4个)。

.container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: repeat(4,minmax(0,1fr));
  grid-template-rows: repeat(2,minmax(0,1fr));
  grid-gap: 5px;
}

.container div {
  background-color: red;
}

body:before {
  content: "";
  display:inline-block;
  padding-top: 50%;
}

body {
  position:relative;
  margin: 0;
}

img {
  max-width: 100%;
  max-height: 100%;
}
<div class="container">
  <div>any contet here</div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/300?image=1069"></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
</div>

你可以使用CSS变量来控制行数或列数,并使其更加通用:

:root {
  --n:6;
  --m:6;
}

.container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: repeat(var(--m),minmax(0,1fr));
  grid-template-rows: repeat(var(--n),minmax(0,1fr));
  grid-gap: 5px;
}

.container div {
  background-color: red;
}

body:before {
  content: "";
  display:inline-block;
  padding-top: calc(var(--n)/var(--m) * 100%);
}

body {
  position:relative;
}

img {
  max-width: 100%;
  max-height: 100%;
}
<div class="container">
  <div>any contet here</div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/300?image=1069"></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
  <div>any contet here</div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/300?image=1069"></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
  <div></div>
  <div></div>
  <div><img src="https://picsum.photos/200/300?image=1069"></div>
  <div></div>
  <div><img src="https://picsum.photos/200/200?image=1062"></div>
  <div>any contet here any contet here</div>
  <div></div>
  <div></div>
</div>


能否解释一下这段代码?body:before { content: ""; padding-top: calc(var(--n)/var(--m) * 100%); } - Fred Hors
@FredHors 它允许保持整个网格的比例...如果我们有相同数量的行和列,我们应该有一个正方形,因此它将在填充中占据100%,因为填充将宽度视为参考,并增加高度,所以高度=宽度...如果我们有n行和m列,则比率为n/m(不再是正方形),因此高度应为(n/m)*宽度,这就是为什么填充需要n/m * 100%。 - Temani Afif
这些不是正方形。 - maracuja-juice

6

** @fcalderan的回答解决了问题,所有功劳归他。 **

显然这会破坏方形的形状,但如果你使用任何文本,一个小调整将有助于提高效果。相反,您可以使用::after伪元素来避免推动或分割潜在内容。据我所知,更改为display:block也消除了vertical-align:top的必要性。

为了进一步保持在使用文本时的长宽比例,我会使文本position:absolute

请查看以下片段,当使用::before::after来说明我的观点。

.container,
.container2 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-gap: 5px;
}
.container div {
  background-color: red;
}

.container div::before {
  content: "";
  padding-bottom: 100%;
  display: inline-block;
  vertical-align: top;
}

.container2 div::after {
  content: "";
  padding-bottom: 100%;
  display: block;
}

.container2 .text {
  position: absolute;  
}

.container2 div {
  background-color: green;
  position: relative;
  overflow: hidden;
}
<div class="container">
  <div>
    <div class="text">Here is some text.</div>
  </div>
  <div>
    <div class="text">Here is some more text.</div>
  </div>
  <div>
    <div class="text">Here is some longer text that will break how this looks.</div>
  </div>
</div>
  
  <hr>
  <div class="container2">
  <div>
    <div class="text">Here is some text.</div>
  </div>
  <div>
    <div class="text">Here is some more text.</div>
  </div>
  <div>
    <div class="text">Here is some longer text that will break how this looks.</div>
  </div>
</div>


我们两种情况下都没有正方形了。 - Temani Afif
你说得没错,@TemaniAfif。我刚刚进行了编辑。 - guitarzero

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