如何在CSS Grid中使最后一行的项目占用剩余空间?

71
有没有一种方法可以强制网格中最后一行的所有项目填充该行,无论它们有多少个?
我不知道网格中会有多少项,因此无法直接针对它们进行操作。我尝试使用grid-auto-flow: dense,但它并没有真正帮助解决问题。
这是我的问题可视化的方式: enter image description here:

div {
  margin:20px auto;
  width: 400px;
  background: #d8d8d8;
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(3, 1fr);
}
span {
  height: 50px;
  background: blue;
}
<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>  
</div>
 


@IvanS95 噢,对不起!我的错 :) 那么他必须使用表格,对吧? - Ahtisham
1
@Ahtisham 我不建议使用用户表,这种特定的布局可能更适合使用Flexbox,因为OP可以使最后一个项目使用剩余空间。 - IvanS95
@IvanS95 你觉得创建两个div怎么样?第一个div的宽度固定,第二个div的宽度动态变化。☺️ - Ahtisham
2
@Ahtisham,这可能比使用flexbox还要更费力。 - IvanS95
我建议您使用flexbox。 - Amitoj Singh Ahuja
这是CSS网格布局和CSS弹性盒子布局之间的主要区别。对于此,请使用Flexbox。Flex可以实现此功能,但是网格布局除非使用一些hacky方法(如部分答案中提到的),否则无法实现。我在这里阅读了文章https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Mastering_Wrapping_of_Flex_Items。 - Mustafa
6个回答

32

通过结合 CSS 规则 nth-child 和 nth-last-of-type,使用 CSS 网格布局完全可以实现。唯一的限制是必须事先知道列数。

.grid {
    display: grid;
    grid-template-columns: auto auto auto;
    justify-items: start;
    grid-gap: 10px;
}

.grid div {
  border: 1px solid #ccc;
  width: 100%;
}

.grid > *:nth-child(3n-1) {
  justify-self: center;
  text-align: center;
}

.grid > *:nth-child(3n) {
  justify-self: end;
  text-align: right;
}

.grid > *:nth-child(3n-1):nth-last-of-type(1) {
  border-color: red;
  grid-column: span 2;
}

.grid > *:nth-child(3n-2):nth-last-of-type(1) {
  border-color: red;
  grid-column: span 3;
}
<div class="grid">
  <div>text</div>
  <div>TEXT</div>
  <div>text</div>
  <div>text</div>
  <div>TEXT</div>
  <div>text</div>
  <div>text</div>
  <div>TEXT</div>
</div>


是的,正如所述,但是当您知道列数时,它完全有效,因此我相信这是您问题的答案。如果列数不同,例如在使用媒体查询时,您也可以使用scss来计算这些条目。 - rainecc
抱歉造成误解,再次感谢您花时间回答问题,但这不是答案 :) 如果您能请阅读原帖,我没有提到我们知道列数,如果您假设了这一点,那么我可以说这不是预定义的值,我们不知道列数。更明确地说,这是为我们在电子商务平台上制作模板而做的,我们已经使用了Flex(同时),但整个想法是CSS不依赖于列数,至少不像您的答案所述的那样。 - Bondsmith
你的CSS显示了"grid-template-columns: repeat(3, 1fr)",而你的要求是如何使项目填充剩余空间,无论有多少个ITEMS。我已经回答了这个问题。如果你需要进一步询问在不知道有多少列的情况下如何实现这一点,请随时提问。 - rainecc
2
将“items”与“columns”混淆 - rainecc
1
原始帖子声明了一个3列网格。如果原始帖子声明了“自适应”和“给定任意数量的列..”,那么这个论点就成立了。但是在这种情况下,这个答案完美地回答了原始问题。感谢@rainecc,这对我的用例非常有效!(实际上我修改为6列,这样我可以让最后两列跨越50%的网格) - simey.me
显示剩余3条评论

22
我认为CSS网格不是你试图构建的布局的最佳选择,至少在它将是动态的并且你不知道容器上会有多少项时不是最佳选择。对于一维布局,Flexbox实际上更好;可能会更难以保持每个元素完全相同的大小,并完全按照您需要的方式使用所有可用空间,但在最后这种情况正是Flexbox的用武之地。
当然,您也可以通过在CSS上进行一些计算来利用100%的宽度。
CSS Grid可能更适合保持行和列对齐,但这是另一种情况。

.container {
  display: flex;
  flex-wrap: wrap;
  box-sizing: border-box;
}

.flex-item {
  width: 30%;
  border: 1px solid #000;
  flex-grow: 1;
  min-height: 120px;
  box-sizing: border-box;
  margin: 0 5px 10px;
  justify-content: space-between;
  text-align: center;
}
<div class="container">
  <div class="flex-item">1</div>
  <div class="flex-item">2</div>
  <div class="flex-item">3</div>
  <div class="flex-item">4</div>
  <div class="flex-item">5</div>
  <div class="flex-item">6</div>
  <div class="flex-item">7</div>
</div>


1
谢谢你的回答。我正在使用Flexbox作为备选方案。我研究网格布局的原因之一(并不是唯一的原因)是为了使用“gap”和其他相关功能。例如,即使可以通过margin模拟gap,但由于我们不知道最后一行中有多少项,因此要消除容器侧面的间隙需要额外的代码。 - Bondsmith
@Ogdila 没问题!很遗憾,目前似乎不可能实现;我刚刚发现了另一个与此问题相同的问题,看起来 CSS Grid 无法实现这一点 https://dev59.com/ya_la4cB1Zd3GeqP0vAa - IvanS95
1
根据规范,您可以在Flexbox中轻松使用例如gap: 0.25rem。不幸的是,只有Firefox和最近的Chrome对此提供了适当的支持。Safari仍然(2021 Q1)无法支持此功能:https://caniuse.com/flexbox-gap - Mikko Rantalainen
@MikkoRantalainen 这很酷,希望它能得到更广泛的应用,这将对这些设计有很大帮助。 - IvanS95
2
好消息,Safari 14.1 支持 flexbox 上的 gap 了。现在只需要等待旧版本消失! - Ric

8

对于那些只想针对最后一个元素进行操作的人,可以尝试使用 grid-column: 1 / -1; 或者如果您正在使用tailwindcss,则可以使用col-span-full

div {
  margin:20px auto;
  width: 400px;
  background: #d8d8d8;
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(3, 1fr);
}
span {
  height: 50px;
  background: blue;
}
div > span:last-of-type {
  grid-column: 1 / -1;
}
<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>  
</div>


抱歉进行灰坟,但您的解决方案仅适用于最后一行只有一个项目的情况。虽然根据OP的问题,它也可能有两个或三个项目。 - qwerty qwerty

2
这在CSS Grid的当前版本(Level 1)中是不可能的。但是,使用flexbox并不太复杂。
你在评论中写道:
“我正在使用Flexbox作为回退方案。我之所以研究网格布局(Grid),其中一个原因(而不是唯一的原因)是要使用“gap”和其他相关功能。例如,即使可以通过margin模拟gap,但由于我们不知道最后一行中有多少项,因此消除容器两侧的间隙将需要额外的代码。”
你是对的:CSS Grid中的grip-gap功能非常方便。但是,您也可以在flexbox中使用边距来模拟其行为,而不会增加太多复杂性。

div {
  display: flex;
  flex-wrap: wrap;
  padding: 0px 0px 5px 5px;
  margin: 20px auto;
  width: 400px;
  background: #d8d8d8;

  }
span {
  flex: 1 0 30%;
  height: 50px;
  margin-top: 5px;
  margin-right: 5px;
  background: blue;
}
<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
  <span></span>
</div>

<div>
  <span></span>
</div>


1
现在 flex box 中也有 gap 属性了!太棒了! - jakhando

2

您可以尝试使用nth-childlast-of-type选择器仅选择超出的项目,最后将该项目跨越整个网格中的列数(使用grid-column: 1 / -1自动完成)。

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 8px;
  row-gap: 8px;
}

.grid-item {
  background: lightblue;
}

.grid-item:nth-child(2n-1):last-of-type {
  background: coral;
  grid-column: 1 / -1;
}
<div class="grid">
  <div class="grid-item">Item 1</div>
  <div class="grid-item">Item 2</div>
  <div class="grid-item">Item 3</div>
  <div class="grid-item">Item 4</div>
  <div class="grid-item">Item 5</div>
</div>


-3

我已经找到了你的问题的答案,我在这里复制了它: https://jsfiddle.net/nmcobalt/dg3mutwv/13/

为了使css更简单并解决这个复杂的问题,建议使用SCSS*而不是纯css。

在SCSS文件中,您必须使用css选择器nth:last-child进行迭代计算子元素,基于模数函数和3列的常数因子。

@mixin setLastChildFluid{
  @for $i from 1 through 10 {    
    $span: 3;
    @if $i % 3 == 0{
      $span: 1;
    } @else if $i % 3 == 1{
      $span: 3;
    } @else if $i % 3 == 2{
      $span: 2;
    } 
    @if $span == 2 {
      span:nth-child(#{$i - 1}){
        &:nth-last-child(2){
          grid-column-end:span 1;
          position:relative;
          bottom:0;
          width:calc(150% + 5px);
          left:0;    
        }
      }
      span:nth-child(#{$i}){
        &:nth-last-child(1){
          grid-column-start:2;
          position:relative;
          bottom:0;
          width:calc(150% + 5px);
          left:calc(50% + 5px);
        }
      }
      
    } @else {
      span:nth-child(#{$i}){
        &:last-child{
            grid-column-end:span #{$span};          
        }
      }
    }
    
  }
}
div {
  position:relative;
  margin:20px auto;
  width: 400px;
  background: #d8d8d8;
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(3, 1fr);
  
  @include setLastChildFluid;
}
span {
  height: 50px;
  background: blue;
  color:yellow;
}

以及以下的HTML标记; 我已经做了两个不同的示例(由div包装)来重现您的查询:

<div>
  <span>1</span>
  <span>2</span>
  <span>3</span>
  <span>4</span>
  <span>5</span>
  <span>6</span>
  <span>7</span>
  <span>8</span>
</div>
<div>
  <span>1</span>
  <span>2</span>
  <span>3</span>
  <span>4</span>
  <span>5</span>
  <span>6</span>
  <span>7</span>
</div>

更改div的数量以查看流体结果。

*SASS是一种预处理器脚本语言,可解释或编译为层叠样式表(CSS)。在此处了解更多信息:https://sass-lang.com/guide


是的,我知道,但使用 SCSS 可以使非常复杂的事情变得更简单。您始终可以使用在线工具将 SCSS 转换为 CSS。 - Vardalas Esteleleloulieth
我必须承认,这种复杂的方式更简单。但是仅仅说他并没有真正询问有关scss的问题,他可能不知道scss是什么。你应该至少解释一下scss,使得查找答案更加方便。 - Jonathan J. Pecany

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