I am adding 3 columns that are 400px wide max and adding space between them using space-between.
.wrap {
display: flex;
flex-wrap: wrap;
align-content: stretch;
justify-content: space-between;
}
.item {
width: 100%;
max-width: 400px;
}
When I make the screen size smaller, the items are not responsive. They just collapse below each other. If I remove flex-wrap I start getting more than 3 columns per row and they are below 400px.
How can I get 3 responsive columns with space between in flex?
Percent for the width can't be used because the space between items has to look the same at any screen size.
You should drop width: 100% if you do not want them to occupy the whole width of the parent. And since you are using flex on the parent, you might as well use flex properties on the children and have these:
.item {
flex-basis: 33%; /* <-- Added in lieu of the width */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
If you only have those 3 children in the parent, then you could also do this:
.item {
flex-grow: 1; /* <-- Lets them grow equally */
flex-shrink: 1; /* <-- Lets them shrink equally. OPTIONAL as 1 is the default */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
The shorthand for the last one is this:
.item {
flex: 1; /* <-- Lets them grow/shrink equally */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
Also, if you only have those 3 children in the parent, you may want to remove flex-wrap: wrap; from .wrapper if you do not want the children elements to wrap. It will not happen in this case, since the children have percentage widths which add up to 100%. But it could be confusing and it contradicts with your intent.
If you want three columns, change the width property to 33% in your .item declaration instead of 100%.
JSFiddle example
Currently, all your "columns" are fighting to be 100% of the parent node. Here's a great explanation of using css flex from css-tricks.com.
Related
I have 3 buttons in a row which all vary in width. I want them to all gain width the same to fill the remaining width of the row, so the widest will still be wider than the others etc.
You can see below that what I've tried to do with flex has resulted in all the buttons being the same width. I know flex-grow can be used to proportionally grow each item, but I can't work out how to get them all to grow in relation to their original size.
You can see in the second row that the blue item is larger than the other two. I just want all three to expand from their current size equally to fill the row.
Thanks
.row-flex {
width: 100%;
display: flex;
flex-direction: row;
}
.button {
flex: 1;
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Short Answer
Switch from flex: 1 to flex: auto.
Explanation
The flex-grow property factors in two key pieces of data:
The free space in the row / column where it is being used.
The value of the flex-basis property.
Distribution of Free Space
The flex-grow property distributes free space in the container among flex items in the same line.
If there is no free space, flex-grow has no effect.
If there is negative free space (i.e., the total length of flex items is greater than the length of the container), then flex-grow has no effect and flex-shrink comes into play.
The flex-basis factor
When flex-basis is 0, flex-grow ignores the size of the content in flex items and treats all space on the line as free space.
This is absolute sizing. All space on the line is distributed.
When flex-basis is auto, the size of the content in flex items is first deducted to determine the free space in each item. flex-grow then distributes the free space among items (based on each item's flex-grow value).
This is relative sizing. Only extra space on the line is distributed.
Here's an illustration from the spec:
Examples:
flex: 1 (absolute sizing)
This shorthand rule breaks down to: flex-grow: 1 / flex-shrink: 1 / flex-basis: 0
Applied to all flex items, this will make them equal length, regardless of content. (Note that in some cases an override of default minimum sizing will be necessary for this effect to occur.)
flex-grow: 1 (relative sizing)
This rule by itself will factor in both content size and available space, because the default value for flex-basis is auto.
flex: auto (relative sizing)
This shorthand factors in both content size and available space because it breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: auto
More variations here: 7.1.1. Basic Values of flex
additional keywords for search: difference between flex-basis auto 0 flex 1 auto
Not sure if this is entirely what you are after, but if you just set flex-grow:1 instead of flex:1;, I think that is your required result:
.row-flex {
width: 100%;
display: inline-flex;
flex-direction: row;
}
.button {
flex-grow: 1;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
Using flex property you can set proportions:
.button {
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.row {
display: flex;
}
.button--1 {
background: red;
flex: 1 1 auto;
}
.button--2 {
background: green;
flex: 2 1 auto;
}
.button--3 {
background: blue;
flex: 3 1 auto;
}
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Minimalistic answer with (hopefully useful, explanatory) alternatives:
HTML:
<div class="row-flex">
Single
Larger title
Another really large title
</div>
CSS:
.row-flex {
display: flex;
}
.button {
flex-grow: 1; /* make the item grow proportionally to its original size */
/* default value is 0, the item does not grow */
/* a meaningful default for flexbox items positioning with */
/* justify-content: <value>; */
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
The following CSS declarations also work because all they do is override the default flex-grow: 0; to the (for the desired behavior required) flex-grow: 1;:
.button {
flex: auto;
...
}
which is a shorthand for:
.button {
flex: 1 1 auto;
...
}
which is a shorthand for:
.button {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
...
}
What I want to achieve (but without the media query):
JsFiddle
#media all and (max-width: 600px) {
#wrapper {
flex-wrap:wrap;
height: 100px;
}
.center {
width: 100%;
order: 3;
}
.left{
width: 50%;
}
.right {
width:50%;
order:2;
}
}
I have 3 elements inside a wrapper, all shrinked. At desktop size, there is some space left over, however when I resize my window to a smaller dimension, at some point, elements run out of space. When that happens, I want to put the middle element to the next line. I have a solution, where the third element goes to the next line, and JSFiddle solution, where the second element goes to the next line, but always at the same static width.
So is it possible to put the middle element to the next line, when all three shrinked elements run out of space?
You can definitely wrap the line without media queries by using flex-wrap, flex-grow, flex-shrink and flex-basis to specify a minimum width that any given item should have:
#wrapper{
display: flex;
width: 100%;
height: 50px;
align-items: center;
text-align: center;
flex-wrap: wrap;
}
.right{
width: 20%;
background-color: blue;
order: 3;
flex-grow: 1;
flex-shrink: 0;
flex-basis: 200px;
}
But it's not possible to change the flex-order based solely on whether the elements "fit". For that you definitely need a media query.
This question already has answers here:
When flexbox items wrap in column mode, container does not grow its width
(9 answers)
Closed 6 years ago.
I have a container and several inner divs.
.container {
display: inline-flex;
flex-flow: column wrap;
max-height: 500px;
}
.element {
width: 200px;
height: 200px;
margin: 10px;
background: #000;
}
Now I have 3 flex columns.
What I expected:
Container's width becomes equal to the sum of columns' width (660px).
What I got:
Container's width becomes equal to the first column's width.
The pen:
http://codepen.io/korsun/pen/zGpQrZ
Why? When I change flex-direction to row and max-height to max-width everything goes just as expected. Is there a way to make my container's width equal to content width?
Your ".wrap" container is set to "inline-block". You will want the container of ".container" to be set to "block" and then a defined with to contain the blocks overall.
Your ".container" is set to "inline-flex" which is then doing the same thing as ".wrap" when you add the inline element into the picture. Setting this back to "flex" should fix your problem.
Your elements inside the container should typically set to "flex: [number]" and a containing width. The current with of "200" is constraining and unfortunately unresponsive. Setting a max-width of 200 will both give it the width desired plus the responsive aspect which you can control with media queries.
http://codepen.io/mmcshinsky/pen/bd927e31d2df2f9180a5b7fcf1df2740/
.wrap {
display: block;
max-width: 660px;
}
.container {
display: flex;
flex-flow: column wrap;
max-height: 500px;
}
.element {
max-width: 200px;
height: 200px;
margin: 10px;
background: #000;
flex: 1;
}
I am trying to use Flexbox with the latest browsers (FF 36, Chrome 41, Opera 28, Safari 8) to achieve full-page holy grail layout. I've gotten it working in everything but Firefox.
The page is split vertically into header, main, footer. main is then split horizontally into three panels. Each panel should scroll independently if their content overflows their bounds. Firefox is the only one that will not do this.
Here is my example: http://jsfiddle.net/bpnjx3v9/1/
html, body {
margin: 0;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
background-color: blue;
}
#header, #footer {
flex: 0 0 100px;
background-color: blue;
}
#main {
background-color: yellow;
flex: 1 0 0px; /** Don't set parent of component to auto */
display: flex;
flex-direction: row;
}
.panel {
display: flex;
flex-direction: column;
flex: 1 0 auto;
overflow: auto;
}
What I don't understand even after reading the spec is how to make #main only use the height allocated to them by the parent. Instead FF seems to make their "intrinsic height" the height of all the child elements. What makes this work in all other browsers but not FF? Bonus points for pointing out the correct section of the spec that explains this.
Ok, so setting min-height: 0px on #main fixes Firefox and keeps everyone else happy.
http://jsfiddle.net/hughes_matt/bpnjx3v9/7/
#main {
background-color: yellow;
flex: 1 0 0px; /** Don't set parent of component to auto */
display: flex;
flex-direction: row;
}
Couldn't quite explain it but then found this in the spec:
By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property. (See Implied Minimum Size of Flex Items.)
main's minimum content height is the height of all its children, the panels. By giving that container explicit permission to be smaller than that, it maxes out at the height of its parent. Chrome/Safari/Opera were happy with a flex-basis: 0px, but Firefox needed min-height in addition to that.
Can anyone tell if this is a violation of the spec? Is FF being too strict or the other browsers being too lenient?
I have the following arrangement via flexbox with flex-wrap and elements able to stretch using flex-grow:
Each item has a margin on all sides. This is to separate the items from each other, but the side effect is the whole block has margins which I'd like to collapse. It could be done with rules like nth-child(-n+3) { margin-top: 0; } but because the container size could vary, there could be any number of items per row and any number of rows. So I'm wondering if flex-box has any way to collapse the outer margins in a setup like this, while retaining the margins between items.
JSBin
The HTML is simply 6 items inside a container.
The CSS (Sass) is as follows:
.container
display: flex
flex-wrap: wrap
background: #eef
align-items: stretch
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
It's a bit of a hack, but you can add a negative margin on the flex container to cancel out the items' margins along the edges, and then move its "background" styling to a parent wrapper-element.
Updated JSBin
Updated CSS (SASS):
.wrapper
background: #eef
border: 1px solid darkgray
.container
display: flex
flex-wrap: wrap
margin: -1em
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
Another hack is to split the margin responsibilities between container and item, each caring about half (say $margin is 1em):
• container cares about its bottom margin and half left + half-right of items:
.container {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap; // Go to next line if not enough space
padding-top: 0; // Let items handle top
padding-left: $margin/2; // Handle half of left
padding-bottom: $margin; // Handle bottom
padding-right: $margin/2; // Handle half of right
}
• items care about top and half left + half right:
.item {
flex-grow: 1; // Use available space
margin-left: $margin/2; // Handle other half of left
margin-right: $margin/2; // Handle other half of right
margin-top: $margin; // Handle top
}
Regarding items size, you can set a width if you want items to look the same.
.item.fixed {
width: 15em;
}
See a demo here.