68

Is there a way to force all the items in the last row, of a grid, to fill the row, no matter how many they are?

I do not know the number of items that will be in the grid so I cannot target them directly. I tried to use grid-auto-flow: dense, but it is not really helping.

This is my question visualized: 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>
 
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Bondsmith
  • 1,343
  • 3
  • 13
  • 27
  • @IvanS95 Oh sorry! My bad :) Then he has to use tables right – Ahtisham Jan 25 '19 at 18:23
  • 1
    @Ahtisham Wouldn't recomment user tables either, this particular layout might be better done with Flexbox since OP can make the last item use the remaining space – IvanS95 Jan 25 '19 at 18:24
  • @IvanS95 What about creating two div's. And keeping the width of first div fixed and later dynamic. ☺️ – Ahtisham Jan 25 '19 at 18:31
  • 2
    @Ahtisham that might be even more work than just using flexbox – IvanS95 Jan 25 '19 at 18:32
  • I would recommend you to use flexbox. – Amitoj Singh Ahuja Jan 26 '19 at 06:41
  • This is the main difference between css grid and css flex. Use flexbox for this . Flex can do this but grid can not unless you use hacky ways as mentioned in some of the answers. I read the article here https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Mastering_Wrapping_of_Flex_Items – Mustafa Nov 26 '21 at 03:50

6 Answers6

31

This is totally possible with CSS grid by combining the CSS rules nth-child and nth-last-of-type. The only caveat is that the number of columns needs to be known in advance.

.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>
rainecc
  • 1,432
  • 16
  • 15
  • Thank you for your answer. Your solution would work only if we know that we have 3 columns in each row, and if, let's say, we have 6 columns, then we have to define the span 5 times by targetting the nth-child(6n-5) and so forth. – Bondsmith May 30 '19 at 11:41
  • Yes, as stated, but it fully works when you know the number of columns, so I believe this is an answer for your question.You could use scss to calculate these entries too, if the number of columns varies, such as when you use media queries. – rainecc Jun 02 '19 at 11:42
  • Sorry for the misunderstanding, again, thank you for the time you put and answered the question, but this is NOT the answer :) If you please read the original post, I did not mention that we know the number of columns and if that is what you assumed, then I can state that it was NOT a predefined value, we do NOT know the number of columns. To is more clear, this is for a template we are making on an eCommerce platform, we have used Flex instead(in the meantime) but the whole idea is that the CSS is not dependent on the number of the column, at least not to the extent your answer is stating. – Bondsmith Jun 04 '19 at 15:37
  • Your css shows "grid-template-columns: repeat(3, 1fr)" and your request is how to make the items fill the remaining space, no matter how many ITEMS there are. I answered that. If you need to ask a further question about how do you do this in a scenario where you don't know how many columns there are, please do so. – rainecc Jun 05 '19 at 15:46
  • I am really not trying to make arguments, and I truly thank you for the answer, but it is not the right answer to my question, sorry about that! – Bondsmith Jun 06 '19 at 01:26
  • This isn't really an answer to the question, which clearly states in the accompanying diagram "we do not know the number of items". So an answer that works only if you know ahead of time the only thing OP won't know ahead of time is, with all due respect, pretty much useless to OP. – TylerH Jul 08 '19 at 21:21
  • 1
    confusing "items" with "columns" – rainecc Jul 08 '19 at 22:10
  • The original post declared a 3 columns grid. If the original post declared "auto-fit" and "given an arbitrary # of columns.." then the argument would stand. But this answers the original question perfectly in the context. Thanks @rainecc this worked perfectly for my use-case! _(I actually modified to 6 columns so I can have the last-two span 50% of the grid)_ – simey.me Dec 13 '22 at 04:56
22

I don't think CSS Grid is the best option for the layout you're trying to build, at least not if it's going to be dynamic and you don't really know how many items will be on the container all the time. Flexbox is actually better for one-dimensional layouts; it might be a little harder to keep everything the exact same size and using all of the available space exactly as you need it, but at the end this type of cases is what Flexbox is built for.

And of course you can make use of 100% width by using few calculations on CSS as well.

CSS Grid might be better to keep rows AND columns aligned, but this is a different case.

.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>
IvanS95
  • 5,364
  • 4
  • 24
  • 62
  • 1
    Thank you for your answer. I am using the Flexbox for the fallback. One (not the only) reason why I am looking into grids is to use "gap" and other features that come with it. For example, even though gap can be simulated by the margin, but since we do not know the number of items in the last row, getting rid of the side gaps (on the side of the container) will require extra code. – Bondsmith Jan 25 '19 at 18:43
  • @Ogdila no problem! Its unfortunate, it just seems it is not possible as of now; I actually just found this other question with the same issue and looks like CSS Grid is not able to achieve this https://stackoverflow.com/q/53394402/8437694 – IvanS95 Jan 25 '19 at 18:47
  • 1
    According to specs you can just say e.g. `gap: 0.25rem` just fine with Flexbox, too. Unfortunately, only Firefox and recent Chrome has proper support for this. Safari is still (2021 Q1) failing to support this: https://caniuse.com/flexbox-gap – Mikko Rantalainen Mar 18 '21 at 14:12
  • @MikkoRantalainen that's cool, hopefully it gets more widely adopted, would help a lot with designs like these – IvanS95 Mar 18 '21 at 15:52
  • 2
    Good news, Safari 14.1 supports gap on flexbox. Just need to wait for the older versions to vanish now! – Ric Sep 13 '21 at 09:50
7

For those looking for an answer to this for just the last element, you can try grid-column: 1 / -1; or col-span-full if you are using tailwindcss.

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>
dr_ermio
  • 811
  • 1
  • 10
  • 21
  • Sorry for necroposting but your solution works only when you have one item in the last row. Although according to the OP question it may have two or three items as well. – qwerty qwerty Aug 24 '22 at 14:22
2

This isn't possible in the current version (Level 1) of CSS Grid. However, it's not too complicated with flexbox.

You wrote in a comment:

I am using the Flexbox for the fallback. One (not the only) reason why I am looking into grids is to use "gap" and other features that come with it. For example, even though gap can be simulated by the margin, but since we do not know the number of items in the last row, getting rid of the side gaps (on the side of the container) will require extra code.

You're right: The grip-gap feature in CSS Grid is quite handy. However, you can emulate the behavior using margins – without much complexity – in flexbox, as well.

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>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
2

You can try selecting only the excedent item with nth-child and last-of-type selectors and finally spaning that last item to the total number of columns in the grid (automatically done with 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>
Sebastian
  • 301
  • 3
  • 4
-3

I have found the answer to your question I have reproduced it here: https://jsfiddle.net/nmcobalt/dg3mutwv/13/

In order to do the css less complicate and solve this complex issue, it is recommended to use SCSS* instead of plain css.

In SCSS file you have to use the css selector nth:last-child with iteration calculating childs based on modulo function and the constant factor of the 3 columns.

@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;
}

and the following html markup; I have done two different examples (wrapped by div) to reproduce your query:

<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>

Change the number of divs in order to see the fluid result.

*SASS is a preprocessor scripting language that is interpreted or compiled into Cascading Style Sheets (CSS). Learn more here: https://sass-lang.com/guide

  • Yes I know, but with scss is become much simpler in a very complex thing. You can always convert scss to css with online tool. – Vardalas Esteleleloulieth Nov 11 '20 at 15:07
  • I have to admit it is more simpler in a complex manner. But just saying as he didn't really ask about scss, he might not know what scss is. You should at least explain a bit about scss to make it more convenient then just search for an answer. – Jonathan J. Pecany Nov 11 '20 at 16:06