Mastery Games

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 min-width and 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 flex-basis.

Flexbox Zombies chapter 7 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 800px (4 200px). Since that total (800px) is larger than the container size (400px) the flex items shrink* to fit.

.container {
  display: flex;
  width: 400px;
}

.item {
  height: 200px;
  /* items have shrunk already */
  flex-basis: 200px;
}

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 flex-basis (200px) is still lower than the container size (250px).

.container {
  display: flex;
  flex-wrap: wrap;
  width: 250px;
}

.item {
  height: 200px;
  /* items haven't starting shrinking yet */
  flex-basis: 200px;
}

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:

.container {
  display: flex;
  flex-wrap: wrap;
  width: 100px;
}

.item {
  height: 200px;
  /* items haven't starting shrinking yet */
  flex-basis: 200px;
}

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 400px (2 * 200px) and the container is 500px. So the items grow to fill the extra space:

.container {
  display: flex;
  width: 500px;
}

.item {
  height: 200px;
  flex-basis: 200px;
  flex-grow: 1;
}

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 200px 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.

.container {
  display: flex;
  width: 500px;
  flex-wrap: wrap;
}

.item {
  height: 150px;
  flex-basis: 200px;
  flex-grow: 1;
}

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:

.container {
  display: flex;
  width: 200px;
  height: 350px;
  flex-wrap: wrap;
  align-content: space-between;
}

.item {
  height: 100px;
  flex-basis: 100px;
}

Or bunch the lines together in the center of the flex container:

.container {
  display: flex;
  width: 200px;
  height: 350px;
  flex-wrap: wrap;
  align-content: center;
}

.item {
  height: 100px;
  flex-basis: 100px;
}

Check out how I used flex-wrap and align-content to great effect on Link's hearts in the Zelda UI:

Flexbox Zombies chapter 10 covers all the align-content options in detail.

wrap-reverse is for masochists only

The final 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.

.container {
  display: flex;
  width: 500px;
  flex-wrap: wrap-reverse;
}

.item {
  height: 150px;
  flex-basis: 200px;
  flex-grow: 1;
}

If that was all that flex-wrap: wrap-reverse changed it wouldn't be too bad. But get this. It also reverses the align-items and 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.

.container {
  outline: 5px solid black;
  display: flex;
  width: 500px;
  height: 500px;
  flex-wrap: wrap-reverse;
  /* 
  wrap-reverse made flex-end 
  be at the TOP! 
  */
  align-items: flex-end;
}

.item {
  height: 100px;
  flex-basis: 100px;
}

.purple {
  /* 
  wrap-reverse made flex-start 
  be at the BOTTOM! 
  */
  align-self: flex-start;
}

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 wrap-reverse!

.container {
  display: flex;
  width: 500px;
  height: 400px;
  flex-wrap: wrap-reverse;
  /* 
  flex-wrap: wrap-reverse 
  made flex-end be the TOP 
  */
  align-content: flex-end;
}

.item {
  height: 100px;
  flex-basis: 100px;
}

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.

Challenge

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.

Flexbox Zombies Game

Flexbox is incredibly powerful. But it's also crazy hard to master. So we all end up depending on a cheat sheet and guessing in the dev tools. Enough of that! Time to master it once and for all, in a way that actually sticks, so you can build any layout you can imagine with flexbox.Master Flexbox