19

Whenever the items inside a flexbox wrap, they tend to stretch the flexbox, leaving extra space on a side. It only happens when items wrap. How do I get rid of that extra spacing?

Screenshot of the issue enter image description here

What I want it to do enter image description here

Code

HTML

<div>
  <div class="red">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
  <div class="green">
    <div></div>
  </div>
</div>

CSS

body > div {
  display: flex;
  width: 34rem;
  justify-content: space-between;
  border: 1px solid black;
}

body > div > div {
  display: flex;
  flex-flow: row wrap;
}

body > div > div.red {
  background: rgba(255, 0, 0, .1);
}

body > div > div.green {
  background: rgba(0, 255, 0, .1);
  flex-shrink: 0;
}

body > div > div > div {
  margin: 1rem;
  height: 5rem;
  width: 5rem;
  background: rgba(0, 0, 0, .1);
}

See an example on JSFiddle

Timofey Drozhzhin
  • 4,416
  • 3
  • 28
  • 31
  • 1
    possible duplicate: http://stackoverflow.com/q/37406353/3597276 – Michael Benjamin Jun 17 '16 at 17:48
  • 1
    @Michael_B Although the question is similar in nature, it's not a duplicate. That question talks about the container not knowing when the text is manually split into new lines, while in my case, the children are not manually split. Update - Although, there is a chance these two questions share the same answer. Perhaps the container, in this case, doesn't have a way to know the width of the children. – Timofey Drozhzhin Jun 17 '16 at 18:00
  • 1
    There is no solution other than specifying a fixed width. – Oriol Jun 17 '16 at 19:46
  • @Oriol I may have to settle for your answer. Unless there is a hack of some sort, there probably isn't a solution other than a fixed width or floating. – Timofey Drozhzhin Jun 17 '16 at 22:14

3 Answers3

5

UPDATE 2

All criteria have been met to the best of my knowledge.

  • No fixed widths
  • Accommodates content of various widths
  • No excessive padding

Changes

  • Red box has justify-content: space-between which reduces the padding on both left and right sides of the red box.
  • Each flex item (with the exception of flex-ghost) is flex: 0 0 auto.
  • Flex-ghost is now pure width, no height with flex: 2 0 auto.
  • Added a little JS to make it interactive.

PLUNKER


UPDATE 1

OP stated that a fixed width will not work due to the fact that if content (i.e. flex items) can change widths and break layout. What really constitutes a fixed layout is that the outer container is rigid having an absolute value measurement and/or max limit length. Being fixed, liquid, responsive, adaptable, sauteed in some white wine, etc. isn't the real problem. What the real problem is that flexbox in a row direction does not handle calculations well when dealing with uneven rows. So to insure a uniform formation of content I find that:

  1. justify-content: space-around will work perfectly if you do the next step.
  2. Add one more flex item to make the rows even, and if you have to have an odd amount of flex items, make the last item invisible either with visibility: hidden or opacity: 0 , but not display: none

Details are in the JS area (no JS added, just it's space being utilized for comments).

SNIPPET

/* Changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CSS
line 1 to 8
|| Needed basic reset
=====================
line 12
|| To demonstrate behavior in liquid layout.
=====================
line 19 to 24
|| Needed some type of measurement, otherwise it 
|| will expand to fill in that extra space on 
|| the right.
|| flex was set to shrink when width has reached
|| it's basis of 62%.
======================
line 22 to 28
|| Width and flex growth/shrink/basis were added
|| for the same reasons as explained of the 
|| prior ruleset.
|| max-width: 380px is the limit for the red 
|| box before the content is askew.
|| justify-content: space-around was added in 
|| order to stabilize it's width.
======================
line 11, 31 to 33
|| Changed rem units to em because it's ideal for
|| a responsive layout. Although rem is a 
|| relative measurement like it's sister
|| property, em, it's based on the root's default
|| so directly changing that measurement will
|| yield a change, whilst with em, only the 
|| container (or parent) needs to resize on the 
|| fly.
======================
line 44 to 46
|| This ghost flex item is the key to the red 
|| boxes' content being able to maintain a 
|| uniformed layout.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HTML
line 8
|| Added an extra div in div.red to be the ghost
|| flex item. Flex items will exhibit a uniform 
|| behavior when there are an equal amount of
|| them in each row.
*/
html,
body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body > div {
  display: flex;
  width: 100vw;
  justify-content: space-between;
  border: 1px solid black;
}

body > div > div {
  display: flex;
  flex-flow: row wrap;
}

body > div > div.red {
  background: rgba(255, 0, 0, .1);
  flex: 0 1 62%;
  min-width: 60%;
  justify-content: space-around;
}

body > div > div.green {
  background: rgba(0, 255, 0, .1);
  justify-content: space-around;
  flex: 0 1 22%;
  width: 20%;
}

body > div > div > div {
  margin: 1em;
  height: 5em;
  width: 4em;
  background: rgba(0, 0, 0, .1);
}

div.red > div:last-of-type {
  opacity: 0;
}
<div>
  <div class="red">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
  <div class="green">
    <div></div>
  </div>
</div>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Thanks for the answer. Like previous answer, this assumes a fix width, which won't work. See example https://jsfiddle.net/5mL3dm3d/5/ – Timofey Drozhzhin Jun 17 '16 at 22:11
  • @timofey Ok, review the update and get back to me.:-) – zer00ne Jun 18 '16 at 00:26
  • 1
    The answer still assumes a fix width to the red region. I need the red region to stretch as much as needed to accommodate children of variable width, yet wrap exactly around the children, not adding the extra padding on the right. – Timofey Drozhzhin Jun 20 '16 at 14:39
  • The key problem you will encounter is that flexbox doesn't handle multiple rows very well unless the content on each row is equal in width. The reason for the ghost content is to even out the rows. As Oriole stated, there is no way to get rid of that unsightly padding without a fixed width. You said that each flex-item can have different widths... going on that idea, then. Standby for update. – zer00ne Jun 20 '16 at 21:36
1

Would setting a max-width on body > div > div.red achieve what you're looking for?

JSFiddle

Nicholas Qiao
  • 96
  • 2
  • 4
  • No. The width is variable; based on contents. Even with the fixed width, if the size of the contents change, the issue will persist, see https://jsfiddle.net/5mL3dm3d/4/ – Timofey Drozhzhin Jun 17 '16 at 18:07
1

It works perfectly in my case when I set width: max-content in wrapper box with display: flex.

DatHoang
  • 11
  • 1