flex-box: shrink before wrap - css

I have a layout with multiple columns, of which some are fixed and others stretch as needed. Therefore, I use flexbox. Additionally, I want and need to use flex-wrap.
The structure is like this:
<div class="row" style="display: flex; flex-flow: row wrap">
<div class="column fixed" style="flex: 0 0 auto"></div>
<div class="column stretch" style="flex: 1 1 auto"></div>
<div class="column fixed" style="flex: 0 0 auto"></div>
</div>
Please see http://jsfiddle.net/mh3rypqj/1/
Now everything works as expected as long as we are talking about empty divs. Once I put a p in the stretch column, wrapping and shrinking behaves differently.
My expected behaviour when space is getting smaller: First shrink, then wrap. Shrink the .stretch. Once min-width is reached, wrap the elements.
The behaviour I get once I put the p in .stretch: First wrap, then shrink. The row is first wrapped. Shrinking only occurs after everything is wrapped.
I want to have First shrink, then wrap. In short, I want the second row in the JSFiddle to behave just like the first. What do I have to do?

Set flex-basis equal to min-width:
.column.stretch {
flex: 1 1 100px; /* or 1 0 100px, and no more need in min-width at all */
max-width: 300px;
min-width: 100px;
background: red;
}
edited JSfiddle example

When using flex-flow, shrinking only ever happens AFTER the flex-basis size is reached. So setting flex-basis: 100px as suggested above, means you want the line to start wrapping once there's not enough room for all the items, including that column's 100px basis. Once room runs out, items will wrap down onto a new line. When space runs out again, a new line will form. This continues until each item has its very own line. Only then - if there's still not space for the basis - will the item(s) start to shrink.
The reason you're seeing a difference with the paragraph of content is because you're not explicitly setting a flex-basis. If flex-basis is set to auto, then it will fallback to the item's width. If width isn't set, the basis falls back to item's size once its content is rendered, then corrected by min and max width. So 300px in this case because you set a max-width. Notice that if you take off the max-width that item gets a full 100% width and instantly gets flowed down to its own line. Then when you resize the page that item starts to shrink because it already has its own line and there's not enough space for that initial size.
Hope that helps!

I'll throw this in, based on what worked for me in the answers here. It grows, it shrinks, it wraps. (Syntax is verbose for clarity.) Note that the flex-basis/min-width value and the user's current browser zoom change what happens. AFAICS.
<div id="outer"
style="
display: flex;
flex-wrap: wrap;
">
<div id="inner"
style="
flex-grow: 1; /* it can grow */
flex-shrink: 1; /* it can shrink */
flex-basis: 225px; /* arbitrary depending on design */
min-width: 225px; /* equal to flex-basis */
max-width: 20%; /* (100% - margins)/number of boxes */
padding: .5em; /* half of desired margin */
">
<...content...>
</div>
</div>

Related

Wrapping text in Flex Item occupies more width than it should? [duplicate]

I'm trying to figure out how flexbox works (supposed to work?…) for cases like below:
.holder {
width: 500px;
background: lightgray;
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
}
.v2 {
width: 320px;
}
.child {
display: inline-block;
border: 1px solid black;
padding: 30px 0px;
text-align: center;
}
<div class="holder">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a
<br>glance</div>
<div class="child">After coverage
<br>ends</div>
<div class="child">Forms &
<br>documents</div>
</div>
JSFiddle here
The problem is that when there's enough space to fit elements, I'm getting a nice tight-fitted children, with even spacing between. (first, top div block)
However, when there's no enough space and text inside children starts wrapping, it all kinda goes in a weird direction - children are not tightly fit anymore, and even though after wrapping, there's enough space around flex children, because there are not properly fit anymore, space-around doesn't really have a chance to work as well (second div block)
However still, IF I add manual line breaks at places where the automatic line breaks occur, everything gets laid out as it "should"… (bottom, third block)
What I'd like is to always have children tightly fitted within their boxes (black borders), and whatever space is left, would be distributed evenly between them, without me having to add manual line breaks (which is not an option in my case)
Is it possible at all?…
In CSS, the parent container doesn't know when its children wrap. Hence, it continues scaling its size oblivious to what's going on inside.
Put another way, the browser renders the container on the initial cascade. It doesn't reflow the document when a child wraps.
That's why the container doesn't shrink-wrap the narrower layout. It just continues on as if nothing wrapped, as evidenced by the reserved space on the right.
The maximum length of the horizontal white space is the length of the element(s) that the container was expecting to be there.
In the following demo, whitespace can be seen coming and going as the window is re-sized horizontally: DEMO
You'll need a JavaScript solution (see here and here)... or CSS media queries (see here).
When dealing with wrapping text, text-align: right on the container may be helpful in some cases.
Have a good look at my Fiddle in which I changed:
.holder width to max-width (in .v classes)
modified .holder to wrap and space-around its children
added 2 more .v classes for clarity
removed the <br>'s
and, most importantly, added flex: 0 0 to .child
Flexbox almost always needs max-width to be set, which is more flexible than width.
Depending on how you need the .children to behave, modify the flex-grow and flex-shrink in flex: 0 0 to meet your needs. (the result of flex: 1 0 looks nice too)
...no Javascript needed...
The Codrops Flexbox Reference is very useful to understand Flexible Box Layout.
The reason why your blocks behave like this is because of CSS rendering.
In the first case in you fiddle the browsers doesn't know when the block gets too small for it's content. So it keeps stretching until it reaches the maximum and then renders the text.
In your last case you tell the browser where to break so it knows that the element should not get wider.
The only way you can easily solve this is by setting the breaks yourself.
If you're looking for a CSS-only solution, you can use something like width: 100px; to set the minimum width of the child and flex: auto; so that it grows.
Example: https://jsfiddle.net/ncvp7gzs/1
(Note this is only tested this on Chrome)

How to stretch children beyond max-width when wrapped (flexbox) [duplicate]

I'm trying to figure out how flexbox works (supposed to work?…) for cases like below:
.holder {
width: 500px;
background: lightgray;
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
}
.v2 {
width: 320px;
}
.child {
display: inline-block;
border: 1px solid black;
padding: 30px 0px;
text-align: center;
}
<div class="holder">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a
<br>glance</div>
<div class="child">After coverage
<br>ends</div>
<div class="child">Forms &
<br>documents</div>
</div>
JSFiddle here
The problem is that when there's enough space to fit elements, I'm getting a nice tight-fitted children, with even spacing between. (first, top div block)
However, when there's no enough space and text inside children starts wrapping, it all kinda goes in a weird direction - children are not tightly fit anymore, and even though after wrapping, there's enough space around flex children, because there are not properly fit anymore, space-around doesn't really have a chance to work as well (second div block)
However still, IF I add manual line breaks at places where the automatic line breaks occur, everything gets laid out as it "should"… (bottom, third block)
What I'd like is to always have children tightly fitted within their boxes (black borders), and whatever space is left, would be distributed evenly between them, without me having to add manual line breaks (which is not an option in my case)
Is it possible at all?…
In CSS, the parent container doesn't know when its children wrap. Hence, it continues scaling its size oblivious to what's going on inside.
Put another way, the browser renders the container on the initial cascade. It doesn't reflow the document when a child wraps.
That's why the container doesn't shrink-wrap the narrower layout. It just continues on as if nothing wrapped, as evidenced by the reserved space on the right.
The maximum length of the horizontal white space is the length of the element(s) that the container was expecting to be there.
In the following demo, whitespace can be seen coming and going as the window is re-sized horizontally: DEMO
You'll need a JavaScript solution (see here and here)... or CSS media queries (see here).
When dealing with wrapping text, text-align: right on the container may be helpful in some cases.
Have a good look at my Fiddle in which I changed:
.holder width to max-width (in .v classes)
modified .holder to wrap and space-around its children
added 2 more .v classes for clarity
removed the <br>'s
and, most importantly, added flex: 0 0 to .child
Flexbox almost always needs max-width to be set, which is more flexible than width.
Depending on how you need the .children to behave, modify the flex-grow and flex-shrink in flex: 0 0 to meet your needs. (the result of flex: 1 0 looks nice too)
...no Javascript needed...
The Codrops Flexbox Reference is very useful to understand Flexible Box Layout.
The reason why your blocks behave like this is because of CSS rendering.
In the first case in you fiddle the browsers doesn't know when the block gets too small for it's content. So it keeps stretching until it reaches the maximum and then renders the text.
In your last case you tell the browser where to break so it knows that the element should not get wider.
The only way you can easily solve this is by setting the breaks yourself.
If you're looking for a CSS-only solution, you can use something like width: 100px; to set the minimum width of the child and flex: auto; so that it grows.
Example: https://jsfiddle.net/ncvp7gzs/1
(Note this is only tested this on Chrome)

How can I make flex items shrink until wrapping is necessary, and then expand to fill the new space?

I have a flexbox parent component with width about 1200px, and several child items with min-width about 400px. Nominally, with a screen width above 1200, and taking into consideration margins and borders, I can fit two child items per row, each about 600px wide.
With a decreasing screen width from about 1200px to about 800px, the two child items gradually shrink down to about 400px. When the screen size goes below about 800px, wrapping occurs, meaning I now have one child item per row.
What I would like is for those child items to expand back to about 800px to fill their rows. What I get is child items that remain at about 400px wide.
If I set grow: 1 on the child items, they start off at one per row, each using the full 1200px.
I'm hoping that there is some combination of min-width, flex-basis, max-width, and grow (and maybe something else) that can achieve my desired result.
I would appreciate any suggestions.
Here's a snippet that I believe achieves what you want:
<div>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
</div>
</div>
<style>
.container {
display: flex;
max-width: 1200px;
flex-wrap: wrap;
}
.box {
outline: solid red 1px;
min-width: 400px;
flex-grow: 2;
/* flex: 2 0 50%; */ /* If you want to ensure that you never get more than 2 items per row */
}
</style>
In sum, the property you want is flex-grow: it ensures that the component will fill up available space on its row up to the specified factor (in this case 2, to go from 400px width up to 800px).
If it's important not to fit more than two elements on a row on wider screens, I added an alternative flex property for that which uses a flex-basis of 50% to make the components "greedier" in flowing onto a row than they would be otherwise.

Flex container width fit content width with flex-wrap: wrap? [duplicate]

I'm trying to figure out how flexbox works (supposed to work?…) for cases like below:
.holder {
width: 500px;
background: lightgray;
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
}
.v2 {
width: 320px;
}
.child {
display: inline-block;
border: 1px solid black;
padding: 30px 0px;
text-align: center;
}
<div class="holder">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a glance</div>
<div class="child">After coverage ends</div>
<div class="child">Forms & documents</div>
</div>
<br>
<br>
<div class="holder v2">
<div class="child">At a
<br>glance</div>
<div class="child">After coverage
<br>ends</div>
<div class="child">Forms &
<br>documents</div>
</div>
JSFiddle here
The problem is that when there's enough space to fit elements, I'm getting a nice tight-fitted children, with even spacing between. (first, top div block)
However, when there's no enough space and text inside children starts wrapping, it all kinda goes in a weird direction - children are not tightly fit anymore, and even though after wrapping, there's enough space around flex children, because there are not properly fit anymore, space-around doesn't really have a chance to work as well (second div block)
However still, IF I add manual line breaks at places where the automatic line breaks occur, everything gets laid out as it "should"… (bottom, third block)
What I'd like is to always have children tightly fitted within their boxes (black borders), and whatever space is left, would be distributed evenly between them, without me having to add manual line breaks (which is not an option in my case)
Is it possible at all?…
In CSS, the parent container doesn't know when its children wrap. Hence, it continues scaling its size oblivious to what's going on inside.
Put another way, the browser renders the container on the initial cascade. It doesn't reflow the document when a child wraps.
That's why the container doesn't shrink-wrap the narrower layout. It just continues on as if nothing wrapped, as evidenced by the reserved space on the right.
The maximum length of the horizontal white space is the length of the element(s) that the container was expecting to be there.
In the following demo, whitespace can be seen coming and going as the window is re-sized horizontally: DEMO
You'll need a JavaScript solution (see here and here)... or CSS media queries (see here).
When dealing with wrapping text, text-align: right on the container may be helpful in some cases.
Have a good look at my Fiddle in which I changed:
.holder width to max-width (in .v classes)
modified .holder to wrap and space-around its children
added 2 more .v classes for clarity
removed the <br>'s
and, most importantly, added flex: 0 0 to .child
Flexbox almost always needs max-width to be set, which is more flexible than width.
Depending on how you need the .children to behave, modify the flex-grow and flex-shrink in flex: 0 0 to meet your needs. (the result of flex: 1 0 looks nice too)
...no Javascript needed...
The Codrops Flexbox Reference is very useful to understand Flexible Box Layout.
The reason why your blocks behave like this is because of CSS rendering.
In the first case in you fiddle the browsers doesn't know when the block gets too small for it's content. So it keeps stretching until it reaches the maximum and then renders the text.
In your last case you tell the browser where to break so it knows that the element should not get wider.
The only way you can easily solve this is by setting the breaks yourself.
If you're looking for a CSS-only solution, you can use something like width: 100px; to set the minimum width of the child and flex: auto; so that it grows.
Example: https://jsfiddle.net/ncvp7gzs/1
(Note this is only tested this on Chrome)

Flexbox grandchild overflowing grandparent's height

I have a flexbox in a side navigation that is overflowing it's granparent's height. The basic structure is:
<div class="holder">
<div class="block-item">content</div>
<div class="flex-nav">
<div class="flex-row"><img src="#"><img src="#"></div>
<div class="flex-row"><img src="#"><img src="#"></div>
<div class="flex-row"><img src="#"><img src="#"></div>
<div class="block-item">content</div>
<div>
.holder { height: 100vh;}
.block-item { display: block;}
.flex-nav { display: flex; flex-flow: column;}
.flex-row { flex: 1 1 0; display: flex;}
img { max-width: 100%;}
Somehow the flex-rows are not shrinking to fit their grandparent's 100vh. Instead, the images are going outside of the view port. From the articles I've read, I'm not sure if a grandchild takes into consideration it's grandparent's height restrictions, though I'm assuming it would. The actual code is slightly different and can be seen in the following codepen:
http://codepen.io/strasbal/pen/zNEMpj?editors=1100
However I'm not sure the exact specifications of Codepen's viewport, it may not show when changes are put into place, so the site url is http://www.webhosting-issues.com
I forked your pen.
Comments are included in the new pen that say /* NEW! */ to help you keep track of what changed, but, basically, since you had already set the height of the overall container at 100vh, I simply assigned a height in vh units to the header and footer that let them maintain the heights they already were, and then did the math to fill in the heights of other child elements.
Overall container is 100vh
Header logo and contact footer are 19vh each
That leaves 62vh for the middle section, made up of three rows
That's 20.666vh per row in the middle section
From there, just set explicit heights for the images and their wrapper links for the inner rows, and you’re was good to go.
One problem you run into is that the text in the links by the images can run out of their container on smaller screens. You could fix that by putting them inside spans and positioning them on top of the images, perhaps with a semi-transparent background.
Hope that works for you.

Resources