As I learned flexbox, I was captivated by the way items grow to fit their container. But, recently I've realized its just as important to think about the way items shrink. Let me show you what I mean.

A typical usecase for flexbox is a set of items that we want to be spaced out evenly in a row. Something like this:

See the Pen 4ace1a957b0500a52a73aeed9f6daedf by Noah Blon (@noahblon) on CodePen.

We create a flex context in a container with display: flex. Flex items are spaced out evenly along the main axis with justify-content: space-between. Everything looks great... until we start adding more items.

See the Pen 9122bd07ea269b234a4b0c68298f77ae by Noah Blon (@noahblon) on CodePen.

Ugh, the images are all squished up! This happens because by default, the value for flex-shrink on items in a flex context is 1. That means that whenever the size of a set of flex items adds up to be larger than our flex context element, the items shrink down to fit.

(NOTE: Since this post, Chrome has changed the way it handles images in flex context. They now maintain their minimum instrinsic size. For this reason, the images are not shrunk to fit anymore. However, the ideas behind this post is still valid.)

The fix is simple: set flex-shrink: 0 on the items that need to remain a fixed size. Setting overflow: auto on the container clears up the issue of the images now overflowing their container.

See the Pen bd735bc1514f747dadcc27fd417e7255 by Noah Blon (@noahblon) on CodePen.

A slightly more complex example is this typical native mobile application style:

See the Pen 29338ef6b21cac31a52c48cce700654a by Noah Blon (@noahblon) on CodePen.

A fixed size header and a footer are clamped to the top and bottom of the viewport and a flexible content area fills up the remaining space. The main area should scroll when the content overflows and the header and footer should remain a fixed size.

To achieve this pattern we set .app to be the full size of the viewport, give it a flex context and set the flex-direction to apply vertically. Our header and footer are a fixed height, and the main content area is set to grow or shrink to fit the remaining space. Unlike flex-shrink, the default value for flex-grow is 0, meaning flex items won't grow to fill space unless you tell them to.

But, we have a problem once we start putting in content. The elements we want to remain a fixed size start to shrink when the content in .main overflows.

See the Pen d59292ea3f737a487bd95255e4833ea4 by Noah Blon (@noahblon) on CodePen.

This happens for two reasons. First, as we already know, all flex items have a flex-shrink value of 1 by default. They will shrink if the content overflows the container setting the flex context. Secondly, the full size of the .main container is used in the flex calculation, not just the visible portion. This is because by default, the flex-basis value of a flex item is auto. The flex-basis is the size basis that is used when calculating how items flex and a value of auto means the full size is used. To fix this, we just stop the header and footer from shrinking with flex-shrink: 0.

See the Pen 9f803e64e831c39fc56be6f2d82fb81d by Noah Blon (@noahblon) on CodePen.

You're going to run into problems like this often when working with flexbox. When I'm approaching a layout, I like to first think about what items need to remain a fixed size, and what items will flex. I also think about whether I need to handle overflow. With those two ideas in mind, flexbox layout becomes a matter of turning off shrinking on items that need to be a fixed size. Items that are flexible are set to grow and shrink, and overflow is handled if necesarry.

For more practical tips about flexbox, you can check out my blog or subscribe to my feed. You can also follow me on Codepen.

Noah Blon is a Client-Side Principal Software Engineer working @TheNerdery in Minneapolis, MN. He loves design, technology and creativity. You can find him on Twitter and Codepen.