Wrap Your Brain Around Flex-Wrap
flex-wrap is Flexbox pitfall #4. See the full list of Flexbox Pitfalls and How to Avoid Them.
Just when you think you’re starting to get the hang of flexbox, you run into a situation where you don’t have enough space on a single line for all of your flex items. No problem right, flex items can wrap! You add
flex-wrap: wrap; and watch as your precious flexbox confidence crumbles to ashes. But don’t worry - there are just a couple of things to know about flex-wrap (and one thing to avoid entirely) and you’ll be feeling flex-awesome again in no time.
when to wrap depends entirely on flex-basis
The first gotcha with
flex-wrap is that flex items will only begin to wrap if their sum total
flex-basis is greater than the size of the flex container. So to understand how
flex-wrap works you also need to have a solid understanding of
flex-basis, which has many nuances of its own. For example
flex-basis falls back to
width when not defined. Also
flex-basis is bounded by the item’s
max-width which affects its “final”
flex-basis value. See The Difference Between Width and Flex-Basis to fully understand this property. If your flex items aren’t wrapping like you expect them to, it’s because of
Flexbox Zombies chapter 7 - “In a Perfect World” covers
flex-basis in detail.
flex-wrap changes how things shrink
By default flex items shrink as soon as their total accumulative
flex-basis is lower than the size of their parent flex container. In this example our container is
400px, and the sum total of all our final
flex-basis values is
200px). Since that total (
800px) is larger than the container size (
400px) the flex items shrink to fit.
But once you tell your container to
flex-wrap, then wrapping become a priority over shrinking. Keep this formula in mind:
continue wrapping to new lines until each flex item has its own line, then begin shrinking items once their flex-basis is greater than the container size.
Notice in this example since we’re wrapping, the items haven’t even started to shrink yet because they just keep wrapping to get their own line and their
200px) is still lower than the container size (
But as soon as each item has its own line and the container size is lower than an items
flex-basis, then the item will shrink:
flex-wrap changes how things grow
flex-wrap also affects how flex items grow. By default if you have items set to grow (
flex-grow: 1) they’ll grow on a single line whenever there’s free space available. In this example the
flex-basis sum is
2 * 200px) and the container is
500px. So the items grow to fill the extra space:
But when you use wrapping, items treat the row they’re on as the only space that matters, and will grow to fill any free space in their own line.
In this example there are three items at
flex-basis each, inside of a
500px wide container. There’s not enough room for them to all fit so the last item drops to a new line. It then treats that line as its very own and grows to fill the entire space inside of it. The remaining two items in the original line also grow a little bit to share the newly created
100px of free space in the first line.
new property to learn
Once your flex items wrap to a new line, you need to learn how to control the positioning of those lines. This is what
align-content is all about. With it you can do cool things like space out the wrapped lines:
Or bunch the lines together in the center of the flex container:
Check out how I used
align-content to great effect on Link’s hearts in the Zelda UI (fast forward to 8min 28seconds):
Flexbox Zombies chapter 10 - “Read Between the Lines” covers all the
align-content options in detail.
wrap-reverse is for masochists only
flex-wrap pitfall to watch out for is that
flex-wrap: wrap-reverse will give your brain a proper mind-bending from which you may never recover. The purpose of this value is to let you reverse the order of your wrapped lines. Usually new wrap lines are created after the existing line(s) like in all the examples above. That means new lines usually show up below when doing horizontal layouts, or to the right when doing vertical layouts. But setting
flex-wrap: wrap-reverse changes that so that new lines show up before existing lines. Above existing line(s) for horizontal layouts, and to the left of them for vertical layouts.
In this example the blue item didn’t have enough room to fit on the same line so it moved to its own line. But this time because of
flex-wrap: wrap-reverse that new line is placed above the original line.
If that was all that
flex-wrap: wrap-reverse changed it wouldn’t be too bad. But get this. It also reverses the
align-self properties! Even when there’s plenty of space so no wrapping is needed. Up is down, down is up, right is left, left is right.
See for yourself: in the code below delete the
flex-wrap: wrap-reverse; line and watch your world flip back right-side up.
flex-wrap: wrap-reverse does this same dizzying trick to the
align-content property - reversing the alignment axis - making
flex-end bunch the lines to the top of the container rather than to the bottom. Thanks
If you’re some kind of super human genius and can think of a way to keep things straight - “the enemy gate is down” or something - then go for it. Otherwise
wrap-reverse should be avoided. I haven’t found a use for it yet myself. Most of the time you can just change the source order of your DOM elements anyways to get the effect you’re after. Even if you never use it yourself, it’s good to know what it does in case you encounter it in the wild.
Wrap your brain (see what I did there…) around the nuances of
flex-wrap by getting some practice: find a UI you like where
flex-wrap would be a good fit and build it yourself. Cement these concepts into muscle memory by shooting the crossbow in Flexbox Zombies chapter 9 - “Get Your Own Line”.