TECH

Your Ultimate Guide to CSS Flexbox

Himayan
Level Up Coding
Published in
13 min readJul 14, 2021

--

Flexbox is an essential tool to setup any layout in your application. It can be a list of things, a set of thumbnails or even a basic navigation bar. Flexbox can help placing things and making them responsive a lot easier, as it defines how your elements grow or shrink by utilizing free space.

Source — Wallpaper Flare

Flex-box is a whole ecosystem of its own — but do not panic, we will get there. I will be breaking it down to parts and keep integrating new pieces as we go along.

Flex-box Model

Any component we build has a structure of a wrapper containing one or more children, and that children can again act as a wrapper to contain one or more children of its own, and so on and so forth. Every HTML DOM element follows this tree pattern.

As an example, we will be using the following tree going forward —

A container with three children

The grey box (a square of 500px) is a container with three children (red, blue and green squares of 100px). We have applied some basic styling in the basics.css file. These styles will remain unchanged throughout the course of this article.

In a flex-box model, a wrapper (referred to as flex-container) and a child (referred to as flex-item) have different roles to play. A flex-container’s properties dictate how its children (along with the unused space) will be positioned inside of it, while the flex-item’s properties dictate whether that item has to stretch or shrink (or even take position of a sibling).

Enough with the theory now — let’s get on with it already.

Flex-container Properties

display

Syntax display: flex
What it does— It essentially turns an element into a flex-container, and all other properties in this section has this one (display: flex) as a prerequisite.

display: flex

What just happened?
The most noticeable change is that the children gets positioned side by side, instead of stacking up (like a block element is supposed to do).

But, why?
It’s time we check out flex-direction.

flex-direction

Syntaxflex-direction: row | row-reverse | column | column-reverse
Defaultrow
What it doesFlex-items are laid out in the flex-container along the axis defined in the its flex-direction.

  • row— left to right
  • column— top to bottom
  • row-reverse — right to left
  • column-reverse— bottom to top
flex-direction

If a flex-direction is not explicitly assigned to a flex-container (i.e. any element with display: flex), it takes the default value — row.

But, what if content overflows?
It’s flex-wrap to the rescue.

flex-wrap

Syntaxflex-wrap: nowrap | wrap | wrap-reverse
Defaultnowrap
What it doesflex-wrap dictates what happens when content inside a flex-container overflows.

  • nowrap— content tries to fit into one line, and overflows if there are restraints.
  • wrap — content gets wrapped into multiple lines (as per flex-direction).
  • wrap-reverse — content gets wrapped into multiple lines (opposite direction of flex-direction).

PRO TIP —
You can use flex-flow as a shorthand for flex-direction and flex-wrap.
As for example —
flex-flow: row wrap; is essentially flex-direction: row; flex-wrap: wrap;

Let’s increase the size of the small boxes to 200px to create a use-case for content overflow —

flex-wrap — default behavior

What just happened?
The default flex-wrap: nowrap is making those boxes shrink down their widths to squeeze into the container. Our boxes are no longer squares, but some weird rectangles.

However, it cannot overpower min-width(or min-height for flex-direction: column), and content overflows to the right (or bottom, respectively).
But, flex-wrap: wrap breaks them into multiple lines, while respecting element’s assigned width —

flex-wrap

SNEAK PEEK —
Did you notice the space between the lines when the content gets wrapped?
Take a look at the align-content section below to understand why.

justify-content

Syntax justify-content: flex-start | center | flex-end | space-between | space-around | space-evenly
Defaultflex-start
What it does— justify-content dictates how the flex-items are positioned along the flex-direction provided in the flex-container.

  • flex-start— items are placed at the start of the container.
  • center— items are placed at the center of the container.
  • flex-end— items are placed at the end of the container.
  • space-between— items are placed with equal space between them, first and last child are at the start and end of the container respectively.
  • space-around— items are placed with equal space around them, the space between any two adjacent item is exactly double the space between the first item (as well as the last) and its closest container boundary. This is because — the gap between first and second item contains both of their spacings, whereas it only takes the first one’s when it comes to the space between the first item and the wall.
  • space-evenly— items are placed in a way that the space between any two adjacent items (as well as the boundaries) are equal.
justify-content

PRO TIP —
When we are placing items using justify-content, we can have the unintended consequence of pushing items outside the container (when content overflows) — in a way that they can not be scrolled to (check example below). Adding a safe keyword can be a life-saver in such cases.

justify-content but safe

align-items

Syntax align-items: stretch | flex-start | flex-end | center | baseline
Defaultstretch
What it does— align-items dictates how the flex-items are positioned along the perpendicular of the flex-direction provided in the flex-container.

To understand this properly, let’s unset the height of the small boxes —

align-items — default behavior

What just happened?
If we do not provide any height (or width, for flex-direction: column) to the items, they stretch to fill up the container. Luckily, we can control this default behavior by adjusting align-items

  • stretch— items stretch to fill the container.
  • flex-start — items are placed at the start of the axis perpendicular to given flex-direction.
  • center— items are placed at the center of the axis perpendicular to given flex-direction.
  • flex-end— items are placed at the end of the axis perpendicular to given flex-direction.
  • baseline— items are aligned according to their baselines.
align-items

PRO TIP —
Similar to justify-content, safe keyword works with align-items too.

align-content

Syntax align-content: stretch | flex-start | center | flex-end | space-between | space-around | space-evenly
Defaultstretch
What it does— align-content dictates how space between the lines are used up, when content is wrapped.
Prerequisite — flex-container must have flex-wrap: wrap | wrap-reverse, since nowrap prevents content from moving on to the next line.

To understand this properly, let’s add flex-wrap: wrap first and make the boxes bigger so that content overflows —

align-content — default behavior

What just happened?
The lines are stretching to fill up the container (since align-content: stretch by default), whereas the items are restricted by the height property. If we unset the height

align-content — default behavior with height: unset

When flex-container is wrapped and the content is moved to next line, the space between the lines can be controlled by this property.

  • stretch— items stretch to fill the space in between the lines.
  • flex-start — lines are positioned at the start of the container with no space in between.
  • center— lines are positioned at the center of the container with no space in between.
  • flex-end— lines are positioned at the end of the container with no space in between.
  • space-between— items are placed in a way that the lines have equal space between them, first and last line are at the start and end of the container respectively.
  • space-around— items are placed in a way that the lines have equal space between them, the space between any two adjacent lines is exactly double the space between the first line (as well as the last) and its closest container boundary.
  • space-evenly— items are placed in a way that the lines (as well as the boundaries) have equal space between them.
align-content

PRO TIPS —
#1 → Similar to justify-content and align-items, safe keyword works with align-content too.
#2 → You can use place-content as a shorthand for align-content and justify-content.
As for example —
place-content: flex-start center; is essentially align-content: flex-start; justify-content: center;

Flex-item Properties

flex-grow

Syntax flex-grow: any positive integer
Default0
What it does— flex-grow dictates how a flex-item grows if there is space available (in the given flex-direction).

A flex-item with flex-grow: 2 tries to take up twice the unused space than a flex-item with flex-grow: 1. This is best explained through examples —

flex-grow

flex-shrink

Syntax flex-shrink: any positive integer
Default1
What it does— flex-shrink dictates how a flex-item shrinks if there is no space available (in the given flex-direction).

When there is no space available, flex-items shrink down to squeeze inside the container. flex-shrink controls the factor by which a flex-item shrinks. A flex-item with flex-shrink: 2 tries to squeeze down by a factor twice than that of a flex-item with flex-shrink: 1.

We are assigning a width of 400px to the blue box, so that the other boxes shrink down to make accommodation—

flex-shrink

PRO TIP —
If you want a flex-item to not shrink down under any circumstances, set flex-shrink: 0.

flex-basis

Syntax flex-basis: auto | 0 | any size value
Defaultauto
What it does— flex-basis defines the default size of the flex-item. All flex-grow / flex-shrink values are factored in along with flex-basis to reach the final size of a flex-item.

What does that even mean?
flex-basis is the final step in understanding how the size of a flex-item is calculated. Let’s dive into it by looking at some use cases —

Case 1 — equal size | equal stretch

We are unset-ting the width, assigning flex-grow: 1 and applying flex-basis: 100px to all the small boxes. We are essentially replacing the width property here with flex-basis, as well as asking them to occupy the rest of the unused space —

equal size | equal stretch

What just happened?
Container size = 500px
Box size before flexing — i.e. flex-basis= 100px
Unused space = 500px — (3 * 100px)= 200px
Total flex grow — every flex-item has flex-grow: 1= 3
Box increases by = 200px * (1 / 3) = 66.67px
Final box size = 100px + 66.67px = 166.67px

Case 2 — double size | equal stretch

We are increasing the flex-basis of the red box to 200px. Let’s see how that changes the layout —

double size | equal stretch

What just happened?
Container size = 500px
red box size before flexing — i.e. flex-basis= 200px
(blue / green) box size before flexing — i.e. flex-basis= 100px
Unused space = 500px — (2 * 100px) — 200px= 100px
Total flex grow — every flex-item has flex-grow: 1= 3
Boxes increases by = 100px * (1 / 3) = 33.33px
Final red box size = 200px + 33.33px = 233.33px
Final (blue / green) box size = 100px + 33.33px = 133.33px

Case 3— double size | double stretch

We are keeping the flex-basis of the red box at 200px, but also increasing the flex-grow: 2. Let’s see how that changes the layout —

double size | double stretch

What just happened?
Container size = 500px
red box size before flexing — i.e. flex-basis= 200px
(blue / green) box size before flexing — i.e. flex-basis= 100px
Unused space = 500px — (2 * 100px) — 200px= 100px
Total flex grow — (blue / green) box has flex-grow: 1, red box has flex-grow: 2= 4
red box increases by = 100px * (2 / 4) = 50px
(blue / green) box increases by = 100px * (1 / 4) = 25px
Final red box size = 200px + 50px = 250px
Final (blue / green) box size = 100px + 25px = 125px

In a nutshell —
flex-basis controls the default size of a flex-item (width|height for flex-direction: row|column respectively). It can take a few other values as well —

  • autoflex-basis takes the width (or height for flex-direction: column) value of the flex-item.
  • 0flex-basis takes the size of its content.
  • any size valueflex-basis takes it as it is.

flex

Syntax flex: initial | auto | none | one-two-three-value
Defaultauto
What it does — A combination of flex-grow, flex-shrink and flex-basis is all you are going to need to size a flex-item. Luckily, we have a shorthand which combines all these properties —

  • initial
    flex: initialflex-grow: 0; flex-shrink: 1; flex-basis: auto;
    flex-item shrinks to fit its content, but never grows to occupy unused space, its default size is based on its assigned width / height.
  • auto
    flex: autoflex-grow: 1; flex-shrink: 1; flex-basis: auto;
    flex-item shrinks to fit its content, and grows to occupy unused space, its default size is based on its assigned width / height.
  • none
    flex: noneflex-grow: 0; flex-shrink: 0; flex-basis: auto;
    flex-item is no longer flexible. It does not shrink or grow, its size is based on its assigned width / height.
  • One value syntax —
    flex: 1flex-grow: 1; flex-shrink: 1; flex-basis: 0;
  • Two value syntax —
    flex: 1 2flex-grow: 1; flex-shrink: 2; flex-basis: 0;
  • Two value syntax —
    flex: 1 100pxflex-grow: 1; flex-shrink: 1; flex-basis: 100px;
  • Three value syntax —
    flex: 1 2 100pxflex-grow: 1; flex-shrink: 2; flex-basis: 100px;

align-self

Syntax align-self: auto | stretch | flex-start | flex-end | center | baseline
Defaultauto
What it does — It overrides the align-items value given to it by flex-container, for that particular flex-item.

align-self

order

Syntax order: any number
Default0
What it does — It dictates which position a flex-item will take. By default, it follows the order in which they are written, but a flex-item with a higher order value is positioned after the others.

order

That essentially ends all the key properties you need to know to get on with flex-box. However, I have discussed a few use-cases in the section below which can help you solve some day-to-day flex problems.

FAQs

#1 — Why are there no justify-items and justify-self?

Flex-box model do not have justify-items and justify-self, because those results can be achieved by margin property (as you will find out in examples below).

  • justify-content — places items in the axis given in flex-direction.
  • align-content — places items in the axis perpendicular to the one given in flex-direction.
  • align-items — controls space between the lines in the axis perpendicular to the one given in flex-direction.
  • margin — controls space between the lines in the axis given in flex-direction (for every flex-item).

#2 — How can I center an element (both horizontally and vertically) using flex-box?

Voila!

centering an element

#3 — How can I corner an element using flex-box?

Adding a margin-left: auto to the green box will move it to the right edge of the container —

cornering to top-right

Whereas, we can use align-self: flex-end to move it to the bottom —

cornering to bottom-right

References

BONUS TIPS —
#1 → Do check out Flexbox Froggy. It’s a fun way of learning and polishing your flex-box skills through an interactive game. Trust me, you would love it !
#2 → You can also check out this extensive course on flex-box by Wes Bos.

Fin

Thank you and congratulations on reaching the end of the article. I hope you find it useful.

While you are here, you can also check out a few of my other articles —

Cheers!

--

--