How to make the items in the last row consume remaining space in CSS Grid?

23,036

Solution 1

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>

Solution 2

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>

Solution 3

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>
Share:
23,036
Bondsmith
Author by

Bondsmith

I run a design company in Jacksonville, FL

Updated on November 20, 2020

Comments

  • Bondsmith
    Bondsmith over 3 years

    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>
     
    • Ahtisham
      Ahtisham over 5 years
      @IvanS95 Oh sorry! My bad :) Then he has to use tables right πŸ˜€
    • IvanS95
      IvanS95 over 5 years
      @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
    • Ahtisham
      Ahtisham over 5 years
      @IvanS95 What about creating two div's. And keeping the width of first div fixed and later dynamic. ☺️
    • IvanS95
      IvanS95 over 5 years
      @Ahtisham that might be even more work than just using flexbox
    • Amitoj Singh Ahuja
      Amitoj Singh Ahuja over 5 years
      I would recommend you to use flexbox.
    • Mustafa
      Mustafa over 2 years
      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 developer.mozilla.org/en-US/docs/Web/CSS/…
  • Bondsmith
    Bondsmith over 5 years
    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.
  • IvanS95
    IvanS95 over 5 years
    @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 stackoverflow.com/q/53394402/8437694
  • Bondsmith
    Bondsmith almost 5 years
    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.
  • rainecc
    rainecc almost 5 years
    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.
  • Bondsmith
    Bondsmith almost 5 years
    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.
  • rainecc
    rainecc almost 5 years
    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.
  • Bondsmith
    Bondsmith almost 5 years
    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!
  • TylerH
    TylerH almost 5 years
    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.
  • rainecc
    rainecc almost 5 years
    confusing "items" with "columns"
  • Vardalas Esteleleloulieth
    Vardalas Esteleleloulieth over 3 years
    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.
  • Jonathan J. Pecany
    Jonathan J. Pecany over 3 years
    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.
  • Mikko Rantalainen
    Mikko Rantalainen about 3 years
    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: caniuse.com/flexbox-gap
  • IvanS95
    IvanS95 about 3 years
    @MikkoRantalainen that's cool, hopefully it gets more widely adopted, would help a lot with designs like these
  • Ric
    Ric over 2 years
    Good news, Safari 14.1 supports gap on flexbox. Just need to wait for the older versions to vanish now!
  • jakhando
    jakhando about 2 years
    Now we have gap property in flex box too! Awesome!