I have a <ul>
that is a flex-box and a bunch of <li>
s in it which are the flex-items.
I am trying to get the <li>
to have a flexible width, that stays between two sizes using min-width and max-width. It works great as long as they are on the same line. However, when they wrap, the <li>
s on the new line use as much space as they can. Which means they are small on the first line, and big on the second line when there are just a few of them.
Is there a way to tell flexbox to keep the items the width after wrapping, while keeping the flexible width?
wrapping demo:
My code looks like this:
<ul> <li> <figure> <img src="http://placekitten.com/g/250/250"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/100/100"> </figure> </li> <!-- ... --> </ul>
And the CSS:
ul { display: flex; flex-wrap: wrap; } li { min-width: 40px; max-width: 100px; flex: 1 0 0; }
Here's a live example on codepen with some extra comments, resize your window to see it wrap.
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.
By default, the child elements of a flexbox container will stretch vertically to fill the height of the container. This can be prevented by using the align-self property on the child element that you do not want to stretch. This Pen is owned by dev on CodePen.
A flexbox item can be set to a fixed width by setting 3 CSS properties — flex-basis, flex-grow & flex-shrink. flex-basis : This property specifies the initial length of the flex item. flex-grow : This property specifies how much the flex item will grow relative to the rest of the flex items.
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 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); } } }
Apply the mixin to your flex item:
.flex-item { @include flex-wrap-fix(100px) }
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); } } }
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)
Finally, a forked version of the original CodePen example with the desired output, using the above mixin:
http://codepen.io/anon/pen/aNVzoJ
It's not the answer to what you want, but it nice to use:
display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
https://codepen.io/omergal/pen/povzJrz
ul { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); } li { min-width: 40px; max-width: 100px; } ul, li { margin: 0; padding: 0; list-style: none; } ul { background-color: tomato; } li { margin: 0.5em; background-color: darkgreen; } img { width: 100%; opacity: 0.5; } figure, img { margin: 0; padding: 0; }
<ul> <li> <figure> <img src="http://placekitten.com/g/250/250"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/101/101"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/201/201"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/150/150"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/80/80"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/111/111"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/40/40"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/110/110"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/75/75"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/89/89"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/150/150"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/32/32"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/61/61"> </figure> </li> <li> <figure> <img src="http://placekitten.com/g/320/320"> </figure> </li> </ul>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With