Flexbox sizing makes it possible to create flexible layouts that fully adapt to the screen. If you set up everything correctly you won’t have to rely on media queries to support different viewports, layouts, and orientations.
In this guide I’ll show you how to use the following flexbox sizing properties:
Filling up Free Space
One of the most challenging aspects of writing CSS is figuring out how to allocate the free space that remains on the screen after the page has been populated with content. At some viewports sizes, you’ll often find there’s too much remaining space and you want to fill it with something. At other viewport sizes, you might find there’s not enough space, and the layout breaks in one way or another.
Flexbox’s sizing properties allow you to make decisions about three kinds of scenarios:
flex-grow: how flex items should behave when there’s a surplus of free space (how they should grow).
flex-shrink: how flex items should behave when there’s a shortage of free space (how they should shrink).
flex-basis: how flex items should behave when there’s exactly as much space as needed.
As flexbox is a one-dimensional layout, as opposed to CSS Grid which is two-dimensional, you can allocate free space along the main axis (whether that be top to bottom, bottom to top, left to right, or right to left). You can set the direction of the main axis using the flex-direction property. If you need a refresher on how this works take a look at my tutorial about flexbox alignment.
The most common flex-direction used on left-to-right websites is row, which means you can allocate free space on the left-to-right axis. This also happens to be the default value of flex-direction, so I’ll use it in the following examples.
1. Positive Free Space: flex-grow
The flex-grow property defines how any extra space in-between flex items should be allocated on the screen. The most important thing to remember about flexbox sizing is that flex-grow doesn’t divide up the entire flex container, only the space that remains after the browser renders all flex items. If there’s no surplus of space, flex-grow has no effect.
Without telling the browser what to do with the remaining space, this is how flex items are allocated on the screen:
The browser has used the default value of flex-grow, which is 0, and gives us total inflexibility. This arrangement might be a good solution for some layouts, however, you can also make the items cover the whole space by setting flex-grow to 1:
As you can see below, the flex items have stretched out and filled the whole available space:
In the above example, all flex items have the same flex-grow value, so they grow at the same rate. However, you can also make them grow according to different ratios. For instance, .item-1 can take up twice as much of the available space as the other items. We would write that as follows:
Similarly, you can set a different flex-grow value for each flex item to make them grow relative to each other. Play around with the values in this example and see how they affect the layout:
2. Negative Free Space: flex-shrink
The flex-shrink property is the opposite of flex-grow. It defines how flex items should behave when there’s not enough space on the screen. This happens when flex items are larger than the flex container.
Without flex-shrink, the following CSS would result in a layout where the items overflow the container, as the total width of the items (3*10rem) is bigger than the container’s width (20rem).
Happily for us, flex-shrink is implied, taking on the default value of 1, giving us a layout where the items fit into the container even though there’s not enough space:
When flex-shrink is 1, flex items are fully flexible and when there’s not enough space, they shrink together with the flex container.
Following the same logic, you can make flex items fully inflexible when there’s negative space on the screen. You only have to set flex-shrink to 0 and the items will overflow the flex container:
Similarly to flex-grow, you can also set a different flex-shrink value for each flex item so that they can shrink relatively to each other. Play around with the values in this example and see what impact they have:
Testing the above demo you might have noticed that larger flex-shrink values lead to narrower flex items. For instance, the following CSS results in a layout where .item-3 is the narrowest item:
This is because flex-shrink defines how much a flex item should shrink compared to other items. Thus, larger flex-shrink values lead to smaller elements, which can make things pretty confusing!
3. No Remaining Space: flex-basis
The last scenario of free space allocation is when there’s exactly as much space on the screen as you need. This is when flex items will take the value of flex-basis.
The flex-basis property defines the initial size of flex items. The default value of flex-basis is auto, which means that the size of the flex items is calculated using either the width or height of the element (depending on if it’s a row-based or column-based layout).
However, when the value of flex-basis is something other than auto, it overrides the value of width (or height in case of vertical layouts). For example, the following CSS overrides the default width: 20rem; rule with a respective value for each flex item:
Besides length units, percentages, and auto, you can also use the content keyword as a value for flex-basis. It will make a flex item as wide as the content it holds.
As flex-basis defines the initial value of flex items, it’s the basis the browser uses to calculate flex-grow and flex-shrink. Note that while flex-grow and flex-shrink have relative values (0, 1, 2, etc.), flex-basis always takes an absolute value (px, rem, content, etc.).
The flex Shorthand
Flexbox’s sizing properties also have a shorthand called flex. The flex property abbreviates flex-grow, flex-shrink, and flex-basis in the following way:
/* Longhand form of default values */
/* Shorthand form of default values */
flex: 0 1 auto;
You don’t necessarily have to list all the three values if you don’t want. You can use flex with one or two values, according to the following rules and assumptions:
/* One relative value: flex-grow */
/* One absolute value: flex-basis */
/* One relative and one absolute value: flex-grow | flex-basis */
flex: 1 20rem;
/* Two relative values: flex-grow | flex-shrink */
flex: 1 2;
/* Three values: flex-grow | flex-shrink | flex-basis */
flex: 1 2 20rem;
/* Fully inflexible layout: equivalent of flex: 0 0 auto */
It might take a while to get used to the flex shorthand, but the W3C docs actually recommend using it, instead of the longhand properties:
“Authors are encouraged to control flexibility using the flex shorthand
rather than with its longhand properties directly,
as the shorthand correctly resets any unspecified components
to accommodate common uses.”
There we have it: you can completely control flexibility with flexbox’s sizing properties! In this tutorial, I used a horizontal layout set by flex-direction: row, so space allocation happened along the horizontal (left to right) axis and flex-grow, flex-shrink, and flex-basis modified the width of the flex items.
If you take what we covered and apply it to a vertical layout set by flex-direction: column, allocation will happen along the vertical (top-to-bottom) axis and the sizing properties will modify the height of the flex items.
This tutorial is the third part of my Comprehensive Guide to Flexbox series. To fully understand how flexbox works, be sure to check out the two previous parts: