How can I allow flex-items to grow while keeping the same size?
This is something that cannot be expressed via CSS Flexbox right now. Someone asked basically this exact question on the CSS Working Group Mailing List a few days ago, and the response was: "At the moment, no, this is not possible. This is a high-priority item for Flexbox 2, though.
You may be able to hack up something like you want using max-width
, though -- that'll prevent flex items (particularly those on the last line) from growing indefinitely. Here's a forked version of your plunk with a nonzero flex-grow, and with max-width: 10em
.
(I chose 10em
arbitrarily; you could also use e.g. max-width: calc(100%/5)
, if you want to make sure each flex item takes up no more than 1/5 of the line, for example.)
How to make flexbox items the same size?
Set them so that their flex-basis
is 0
(so all elements have the same starting point), and allow them to grow:
flex: 1 1 0px
Your IDE or linter might mention that the unit of measure 'px' is redundant
. If you leave it out (like: flex: 1 1 0
), IE will not render this correctly. So the px
is required to support Internet Explorer, as mentioned in the comments by @fabb;
How to keep wrapped flex-items the same width as the elements on the previous row?
TL;DR
This is not something I'd call a solution per se, but it's a rather elegant workaround that only uses media queries, and more importantly no JavaScript!
Mixin (SCSS):
@mixin flex-wrap-fix($flex-basis, $max-viewport-width: 2000px) {
flex-grow: 1;
flex-basis: $flex-basis;
max-width: 100%;
$multiplier: 1;
$current-width: 0px;
@while $current-width < $max-viewport-width {
$current-width: $current-width + $flex-basis;
$multiplier: $multiplier + 1;
@media(min-width: $flex-basis * $multiplier) {
max-width: percentage(1/$multiplier);
}
}
}
Usage:
Apply the mixin to your flex item:
.flex-item {
@include flex-wrap-fix(100px)
}
Update:
The above mixin should do the trick, as long as you your flex container width matches your viewport size, as is the case in OP's example. Media queries won't help you otherwise, because they're always based on the viewport width. However, you could use the css-element-queries
library and its element queries instead of browser media queries. Here's a mixin that you can apply to the flex container:
@mixin flex-container-wrap-items($flex-basis, $max-expected-width: 2000px) {
display: flex;
flex-wrap: wrap;
> * {
max-width: 100%;
flex-grow: 1;
flex-basis: $flex-basis;
}
$multiplier: 1;
$current-width: 0px;
@while $current-width < $max-expected-width {
$current-width: $current-width + $flex-basis;
$multiplier: $multiplier + 1;
&[min-width~="#{$flex-basis * $multiplier}"] > * {
max-width: percentage(1/$multiplier);
}
}
}
Explanation:
Let's say, as per the OP's example, we want each item to have a maximum width of 100px
, so we know that for a browser width of 100px
we can fit one item per row, and so on:
| Viewport Width | Max Item Count Per Row | Item Width (min-max) |
|----------------|------------------------|----------------------|
| <= 100 | 1 | 0px - 100px |
| <= 200 | 2 | 50px - 100px |
| <= 300 | 3 | 50px - 100px |
| <= 400 | 4 | 50px - 100px |
| <= 500 | 5 | 50px - 100px |
| <= 600 | 6 | 50px - 100px |
We can write media queries to create the following rules:
| Viewport Width | Max Item Count Per Row | Item Max Width | Calculation |
|------------------------------------------------------------------------|
| <= 100px | 1 | 100% | (100/1) |
| <= 200px | 2 | 50% | (100/2) |
| <= 300px | 3 | 33.33333% | (100/3) |
| <= 400px | 4 | 25% | (100/4) |
| <= 500px | 5 | 20% | (100/5) |
| <= 600px | 6 | 16.66666% | (100/6) |
Like this:
li {
flex: 1 0 0
max-width: 100%;
}
@media(min-width: 200px) {
li { max-width: 50%; }
}
@media(min-width: 300px) {
li { max-width: 33.33333%; }
}
@media(min-width: 400px) {
li { max-width: 25%; }
}
@media(min-width: 500px) {
li { max-width: 20%; }
}
@media(min-width: 600px) {
li { max-width: 16.66666%; }
}
Of course, that's repetitive, but most likely you're using some sort of preprocessor, which can take care of the repetitiveness for you. That's precisely what the mixin in the above TL;DR section does.
All we have to do now is to specify 100px
as our flex-basis
, and optionally the maximum browser window width (defaults to 2000px
) to create the media queries for:
@include flex-wrap-fix(100px)
Example
Finally, a forked version of the original CodePen example with the desired output, using the above mixin:
http://codepen.io/anon/pen/aNVzoJ
CSS Keep all flexbox children elements the same size
You have 2 ways of doing this:
flex-grow: 0 (fiddle)
If you set flex-grow
to 0 you are telling the items to keep their width and expand the empty space. Using flex-grow: 1
the items will expand the width to fit the space.
invisible items (fiddle)
Add some invisible items after the normal items with the same flex properties. You will get a left aligned look.
In this solution there will be the same number of items in all visible rows so make sure to add enough invisible items to work properly on larger screens.
How can a flex item keep the same dimensions when it is forced to a new row?
Maybe an invisible flex item in the last slot will work for you.
Add this code to your CSS:
.container::after {
content: "";
flex-grow: 1;
max-width: 450px;
min-width: 350px;
}
DEMO
UPDATE
I forgot to add one rule, which caused a slight overflow to the right of the pseudo-element.
.container::after {
content: "";
flex-grow: 1;
max-width: 450px;
min-width: 350px;
margin-right: 10px; /* to match the other flex items */
}
REVISED DEMO
More details in this related post: Properly sizing and aligning the flex item(s) on the last row
Can I shrink flexbox items into same size when flex items are bigger than the flex container?
I would use display: grid
instead of display: flex
to achieve this. Here is an example:
.flex-container { font-size: 12px; display: grid; grid-template-columns: 1fr; grid-template-rows: repeat(2, minmax(minmax(0, auto), 50%)); width: 200px; height: 500px; border: 1px solid #dadfe3;}
.flex-item { min-height: 0; overflow: auto; margin: 0 20px;}
.flex-item div { margin: 4px 0; background-color: #f0f9ff; color: #2f88ff;}
<body> <div class="flex-container"> <div class="flex-item"> <input type="text" placeholder="filter 1"> <div>item content 1</div> <div>item content 2</div> <div>item content 3</div> <div>item content 4</div> <div>item content 5</div> <div>item content 6</div> </div> <div class="flex-item"> <input type="text" placeholder="filter 2"> <div>item 1</div> <div>item 2</div> <div>item 3</div> <div>item 4</div> <div>item 5</div> <div>item 6</div> <div>item 7</div> <div>item 8</div> <div>item 9</div> <div>item 10</div> <div>item 11</div> <div>item 12</div> <div>item 13</div> <div>item 14</div> <div>item 15</div> </div> </div></body>
Prevent a flex items height from expanding to match other flex items
This is an old solution.
My answer is superseded by this new answer by Aaron usingalign-self
. That is a better solution that does not rely on a CSS quirk.
As long as the flex container has no height itself, you can set height: 0%
on the first flex item. Because it has no height to inherit from its parent, any percentage height will cause it to collapse. It will then grow with its contents.
Example
In this example I have removed the -webkit
prefix. It's only really required for Safari and the prefix can be added above the non-prefixed version. I also removed flex-direction: row
as it is the default value.
.container {
display: flex;
}
.flexbox-1 {
flex: 1;
height: 0%;
border: solid 3px red;
}
.flexbox-2 {
flex: 2;
border: solid 3px blue;
height: 200px;
margin-left: 10px;
}
<div class="container">
<div class="flexbox-1">.flexbox-1</div>
<div class="flexbox-2">.flexbox-2</div>
</div>
Flexbox not giving equal width to elements
There is an important bit that is not mentioned in the article to which you linked and that is flex-basis
. By default flex-basis
is auto
.
From the spec:
If the specified flex-basis is auto, the used flex basis is the value of the flex item’s main size property. (This can itself be the keyword auto, which sizes the flex item based on its contents.)
Each flex item has a flex-basis
which is sort of like its initial size. Then from there, any remaining free space is distributed proportionally (based on flex-grow
) among the items. With auto
, that basis is the contents size (or defined size with width
, etc.). As a result, items with bigger text within are being given more space overall in your example.
If you want your elements to be completely even, you can set flex-basis: 0
. This will set the flex basis to 0 and then any remaining space (which will be all space since all basises are 0) will be proportionally distributed based on flex-grow
.
li {
flex-grow: 1;
flex-basis: 0;
/* ... */
}
This diagram from the spec does a pretty good job of illustrating the point.
And here is a working example with your fiddle.
Better way to set distance between flexbox items
- Flexbox doesn't have collapsing margins.
- Flexbox doesn't have anything akin to
border-spacing
for tables (edit: CSS propertygap
fulfills this role in newer browsers, Can I use)
Therefore achieving what you are asking for is a bit more difficult.
In my experience, the "cleanest" way that doesn't use :first-child
/:last-child
and works without any modification on flex-wrap:wrap
is to set padding:5px
on the container and margin:5px
on the children. That will produce a 10px
gap between each child and between each child and their parent.
Demo
.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;
padding: 5px; /* this */
}
.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;
margin: 5px; /* and that, will result in a 10px gap */
}
.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
How to prevent content from re-sizing a flex item?
When you tell a flex item to flex: 3
(Item 6) or flex: 1
(Items 5 & 7), here's how that shorthand property breaks down:
flex: ? = <flex-grow>, <flex-shrink>, <flex-basis>
flex: 3 = flex-grow: 3, flex-shrink: 1, flex-basis: 0
flex: 1 = flex-grow: 1, flex-shrink: 1, flex-basis: 0
In both cases, the flex-shrink
factor is 1, meaning the flex item is allowed to shrink proportionally.
To prevent the flex items from shrinking, which may be causing the misalignment, I would change the flex-shrink
to 0.
Instead of flex: 3
and flex: 1
try:
flex: 3 0 0;
flex: 1 0 0;
More details in the flexbox spec: 7.1.1. Basic Values of flex
But you may have another problem. You wrote:
Note that items 5 and 7 are setup the same way in css, with
flex
values of1
. I.e. item 6 is 3 times the height of items 5 and 7. As such, when item 6 resizes, the 3:1 ratio is maintained.
This is not how the flex-grow
property works.
By applying flex-grow: 3
to a flex item you are telling it to consume three times more available space than flex items with flex-grow: 1
. This does not necessarily mean Item 6 will be three times the size of Items 5 and 7.
Learn more about how flex-grow
works here: flex-grow not sizing flex items as expected
As an alternative sizing method, you may want to use the flex-basis
property. Try flex: 0 0 60%
on Item 6, and flex: 0 0 20%
on Items 5 and 7.
Related Topics
Setting Svg Element Width/Height Attributes Using CSS in Firefox
How to Override Max-Width for Specific Div
Chrome Developer Tools: Inspect Prettified CSS
Jquery Mobile Page Transition Without Jquery Mobile
Change the Number of Columns and Rows in a Grid as the Number of Items Increase
Css3 Transition from Width Auto to "N" Px
Firefox Animation Not Starting on Toggle Display Style
Alternative to Page-Break-Inside:Avoid Because of Compatibility Issues
How to Remove Bullets from Numbered Toctree in Restructured Text
Position Div Center Horizontal and Vertical
Using Class Set in Media Query as Mixin in Less
How to Layer Box-Shadows Using Z-Index
Zoom Out Shiny App at Default in Browser
Less CSS - Accessing Classes Further Up the Dom Tree from Within a Nested Class
Align a Bootstrap Navbar to the Right
How to Put Text Inside Radio Button