Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Improving balance in flexbox lines

Tags:

css

flexbox

So let's say I have a flexbox where, for the sake of example, each element contains an image. The purpose of flexbox in this case is to spread them evenly.

Seems easy enough. Let's try it.

#flex {
  width: 350px;
  display: flex;
  flex-wrap: wrap;
}
#flex>div {
  flex: 1 1 auto;
  border: 1px solid black;
  text-align: center;
}
#flex>div>img {vertical-align:bottom}
<div id="flex">
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
</div>

... Oh dear. That's not very well-balanced, is it?

In my actual use case, the width is 100% as it is part of a responsive design. The problem is that at certain widths, the items end up with just one or two too many to fit on a given line, leaving the trailing item(s) to be unreasonably wide. On smaller screens, not an issue. But if the element ends up being 1920px wide when all the others are closer to 200, well... you get the idea.

Is there any way to improve the balance in flex element wrapping, or is this the best I can hope for?

like image 289
Niet the Dark Absol Avatar asked Oct 03 '15 18:10

Niet the Dark Absol


People also ask

How do you align rows in a flexbox?

By default items start from the left if flex-direction is row , and from the top if flex-direction is column . You can change this behavior using justify-content to change the horizontal alignment, and align-items to change the vertical alignment.

How do you add a gap to a flex item?

To set space between the flexbox you can use the flexbox property justify-content you can also visit all the property in that link. We can use the justify-content property of a flex container to set space between the flexbox.

How do you show 3 items per row in flexbox?

For 3 items per row, add on the flex items: flex-basis: 33.333333% You can also use the flex 's shorthand like the following: flex: 0 0 33.333333% => which also means flex-basis: 33.333333% .


3 Answers

This seems something currently not possible but planned for Flexbox Level 2.

The planned features list isn't much detailed but I think it would be one of those:

  • Solve the “items on the last line get way too big when you're flexing” problem. More generally, “make items have a consistent flexed size, regardless of how much extra space is on each line”.
    • Possible solution - calculate minimum values of 1fr and alignment free space across the entire flexbox (instead of per-line) and use that.
  • Flex line balancing.
like image 79
Oriol Avatar answered Oct 23 '22 21:10

Oriol


Since you commented In the example above, two rows of two would be nice. You will need to specify flex-basis: 49% which is equivalent to width: 49%. 49% since it involves the white-space as well.

#flex {
  width: 350px;
  display: flex;
  flex-wrap: wrap;
}
#flex>div {
  flex: 1 1 49%;
  border: 1px solid black;
  text-align: center;
}
#flex>div>img {vertical-align:bottom}
<div id="flex">
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
<div><img src="http://placehold.it/100x32" /></div>
  <div><img src="http://placehold.it/100x32" /></div>
</div>

The last element is spanning the whole width because of flex-grow: 1. You can remove it to provide proper balancing of wrap.

#flex {
  width: 350px;
  display: flex;
  flex-wrap: wrap;
}
#flex>div {
  flex: 0 1 auto;
  border: 1px solid black;
  text-align: center;
}
#flex>div>img {
  vertical-align: bottom
}
<div id="flex">
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
  <div>
    <img src="http://placehold.it/100x32" />
  </div>
</div>
like image 35
m4n0 Avatar answered Oct 23 '22 20:10

m4n0


After battling with this for a while, I just went with floats instead. Flex model so far just doesn't deal with this well.

However, if you really want to, you can do some crazy selector stuff like this:

// in case of e.g. 7 items, 10 items, etc
.item:nth-child(3n+1):nth-last-child { 
  max-width: 33%;
}

// in case of e.g. 8 items, 11 items, etc
.item:nth-child(3n+1):nth-last-child(2) {
  max-width: 33%;
}
.item:nth-child(3n+2):nth-last-child {
  max-width: 33%;
}

(You can scale this to any number of columns. This is obviously simpler if using a CSS compiler like Sass.)

like image 28
mahemoff Avatar answered Oct 23 '22 20:10

mahemoff