Targeting flex items on the last or specific row

HtmlCssFlexbox

Html Problem Overview


My problem is that I want the flexbox with variable range width, and all works well, but not on the last row. I want the same dimension for all children even where the row is not full of children (the last row).

#products-list {
    position:relative;
    display: flex;
    flex-flow: row wrap;
    width:100%;
}

#products-list .product {
    min-width:150px;
    max-width:250px;
    margin:10px 10px 20px 10px;
	flex:1;
}

I created a dynamic situation in jsFiddle

My flex divs can shrink until 150px and grow up to 250px, but all must be with the same size (and obviously I want a CSS solution, with JS I know the way).

Html Solutions


Solution 1 - Html

Unfortunately, in the current iteration of flexbox (Level 1), there is no clean way to solve the last-row alignment problem. It's a common problem.

It would be useful to have a flex property along the lines of:

  • last-row
  • last-column
  • only-child-in-a-row
  • alone-in-a-column

This problem does appear to be a high priority for Flexbox Level 2:

Although this behavior is difficult to achieve in flexbox, it's simple and easy in CSS Grid Layout:

In case Grid is not an option, here's a list of similar questions containing various flexbox hacks:

Solution 2 - Html

As a quick and dirty solution one can use:

.my-flex-child:last-child/*.product:last-child*/ {
  flex-grow: 100;/*Or any number big enough*/
}

Solution 3 - Html

There is a great solution that works always. add a div with class product (The same class for other items that are under flex) and add a style for this div:height:0px; you need to add as many dives that are possible to be in one row.

<div class="product" style="height:0px">

as many that can be in one row. That's all. Works always.

Solution 4 - Html

I was having a similar challenge with menu rows. I wanted more spacing on the top of the second row of menu items.

The use of flex-box's row-gap worked well.

https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap

.menu {
  display: flex;
  flex-wrap: wrap;
  row-gap: 10px;
 }

This added a margin-top type effect to menu items were wrapped to the second line.

Solution 5 - Html

You could try using grid instead of flexbox here:

#products-list {

  display: grid;
  grid-gap: 5px;
  grid-template-columns: repeat(auto-fit, minmax(100px, 250px)); //grid automagic
  justify-content: start; //start left

}

Fiddle link

Solution 6 - Html

I used this workaround, even if it's not very elegant and it doesn't use the power of Flexbox.

It can be carried out on the following conditions:

  • All the items have the same width
  • The items have a fixed width
  • You use SCSS/SASS (can be avoided though)

If this is the case, you can use the following snippet:

 $itemWidth: 400px;
 $itemMargin: 10px;

html, body {
  margin: 0;
  padding: 0;
}

.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 0 auto;
  border: solid 1px blue;
}

@for $i from 1 through 10 {
  @media only screen and (min-width: $i * $itemWidth + 2 * $i * $itemMargin) {
    .flex-container {
      width: $i * $itemWidth + 2 * $i * $itemMargin;
    }
  }
}

.item {
  flex: 0 0 $itemWidth;
  height: 100px;
  margin: $itemMargin;
  background: red;
}

<div class="flex-container">
  <div class="item"></div>
  <div class="item" style="flex: 500 0 200px"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Here I have created an example on codepen which also implements margin.

The second and the third conditions can be avoided respectively using css variables (if you decided to provide support for it) and compiling the above scss snippet.

Well, it's true, we could do it also before flexbox, but display: flex can be still essential for a responsive design.

Solution 7 - Html

A simple trick adds a flexible space to fill the rest of the last row:

#products-list{
	display:flex;
	flex-flow: row wrap;
	justify-content:space-between;
}
#products-list::after {
    content: "";
    flex: auto;
    flex-basis: 200px;/*your item width*/
    flex-grow: 0;
}

But you shouldn't use margins on items then. Rather wrap them into containers with padding.

Solution 8 - Html

I was facing this same issue where I wanted to have a variable number of items in a resizable container. I wanted to use all of the horizontal space, but have all of the flex items at the same size.

I ultimately came up with a javascript approach that dynamically added padding spacers as the container was resized.

    function padLastFormRow() {
        let topList = [];
        let nSpacersToAdd = 0;
        $('#flexContainer').find('.formSpacer').remove();
        $('#flexContainer').find('.formItem').each(function(i, formItem) {
            topList.push($(formItem).position().top);
        });

        let allRowLengths = getFlexLineLengths(topList);
        let firstRowLength  = allRowLengths[0];
        let lastRowLength   = allRowLengths[((allRowLengths.length) - 1)];

        if (lastRowLength < firstRowLength) {
            nSpacersToAdd = firstRowLength - lastRowLength ;
        }

        for (var i = 1; i <= nSpacersToAdd; i ++) {
            $('#flexContainer').append(formSpacerItem);
        }
    }

Please see my Fiddle: http://jsfiddle.net/Harold_Buchman/z5r3ogye/11/

Solution 9 - Html

If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this:

.container{
  display: flex;
  flex-wrap: wrap;
  background: yellow;
}

.item{
  width: calc((100% - 2*10px)/3);
  height: 50px;
  background: blue;
  color: white;
  margin-right: 10px;
  margin-bottom: 10px;
  padding: 5px;
  box-sizing: border-box;
}

// last item of each row
.item:nth-child(3n){
  margin-right: 0;
  background: green;
}

// last 3 items
.item:nth-last-child(-n+3){
  margin-bottom: 0;
  font-size: 150%;
}

<div class="container">
  <div class="item" >1</div>
  <div class="item" >2</div>
  <div class="item" >3</div>
  <div class="item" >4</div>
  <div class="item" >5</div>
  <div class="item" >6</div>
  <div class="item" >7</div>
</div>

Solution 10 - Html

If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this to remove the margin of the last 3 items:

.container{
  display: flex;
  flex-wrap: wrap;
  background: yellow;
}

.item{
  width: calc((100% - 2*10px)/3);
  height: 50px;
  background: blue;
  color: white;
  margin-right: 10px;
  margin-bottom: 10px;
  padding: 5px;
  box-sizing: border-box;
}

/* last item of each row */
.item:nth-child(3n){
  margin-right: 0;
  font-size: 150%;
}

/* last 3 items */
.item:nth-last-child(-n+3){
  margin-bottom: 0;
  background: green;
}

<div class="container">
  <div class="item" >1</div>
  <div class="item" >2</div>
  <div class="item" >3</div>
  <div class="item" >4</div>
  <div class="item" >5</div>
  <div class="item" >6</div>
  <div class="item" >7</div>
</div>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBaroView Question on Stackoverflow
Solution 1 - HtmlMichael BenjaminView Answer on Stackoverflow
Solution 2 - HtmlBoris D. TeoharovView Answer on Stackoverflow
Solution 3 - HtmlsimiView Answer on Stackoverflow
Solution 4 - HtmlkaleemclarksonView Answer on Stackoverflow
Solution 5 - HtmlDamjan OstrelicView Answer on Stackoverflow
Solution 6 - HtmlCristian TraìnaView Answer on Stackoverflow
Solution 7 - HtmlFankyView Answer on Stackoverflow
Solution 8 - HtmlHaroldB2View Answer on Stackoverflow
Solution 9 - HtmlDavidView Answer on Stackoverflow
Solution 10 - HtmlDavidView Answer on Stackoverflow