A comprehensive guide to CSS flexbox layout

Flex container properties
flex-direction | flex-wrap | flex-flow | justify-content | align-items | align-content

Flex items properties
flex-grow | flex-shrink | flex-basis | flex
align-self | order

Introduction

CSS Flexible Box Layout Module (Flexbox) is a direction-agnostic one-dimensional layout method for arranging items in rows or columns.

Direction-agnostic means that it's free from any directional constraints (as an example, block layout mode is vertically biased and inline layout mode is horizontally biased).

One-dimensional means that it deals with layout in one dimension at a time - either as a row or as a column (opposed to CSS Grid Layout which is a two-dimensional model - controls columns and rows together).

Before flexbox, creating web pages was really difficult (we had to use floats, position etc.). With flexbox all these past problems are gone.

Flexbox dictates how space is distributed, content is aligned, and displays are visually ordered, enables the appearance of stretching, shrinking, reversing, and even rearranging the appearance of content without altering the underlying markup. If it is confusing, don't worry, we will discuss all these later.

How to start with flexbox

Flexbox works on an axis grid system and it's a parent and child relationship.

Understanding main and cross axes

When you work with flexbox always think in terms of two axes: the main axis and the cross axis. The main axis is defined by the flex-direction property ( which we will discuss below), and the cross axis runs perpendicular to it. The "main" term is always in connection with flex items. The "cross" term is always in connection with flex lines (when flex items wrap onto more than one line - we will discuss when this happens). In flexbox, no matter what we do, everything refers back to these two axes (main and cross). Therefore it is very important to understand how they work.

We also need to understand the dimensions and sizes related to main and cross sizes. Main and cross axes have both a start and an end. For example, when flex-direction property is set to row, the main start is on the left of the flex container, main end is on the right of the flex container, cross start is on the top of the container and cross end is at the bottom of the container. In the same situation, when flex-direction property is set to row, main dimension is horizontal, main size is width, cross dimension is vertical and cross size is height. If this is confusing, don't worry, the below image will help you to understand this much better.

Also, to have even a better picture about this, the table below will show you all dimensions and directions of the main and cross axes, along with their start points, end points, in left-to-right layout.

The first step

To use flexbox you need to declare display: flex; or display: inline-flex; on an element (a nav, div, ul etc.). This element becomes a flex container and the items inside it become flex items.

The difference between display: flex; and display: inline-flex; is that the first one behaves like block element while the second one behaves like inline element:

In the above image, the light blue rectangle is the flex container and the squares inside are the flex items.

Flex container properties

Flexbox is really powerful and with just a few lines you can easily create a layout.

Let's check the properties which can be applied to the flex container.

It is important to know that all examples and explanation in this article refer to left-to-right (LTR) languages (like English). For right-to-left (RTL) languages (Arabic, Hebrew) I will need to write another article, if needed.

The flex-direction property

This property is used to control the main axis along which the flex items get laid out. The layout can go from top to bottom, left to right, right to left, or even bottom to top.

FLEX-DIRECTION
Values: row | row-reverse | column | column-reverse
Default value: row

The flex-wrap property

This property allows flex items to wrap onto multiple flex lines (rows or columns of flex items) instead of having flex items overflow the container or shrink as they remain on one line. The flex-wrap property controls whether the flex container is limited to being a single-line container or is allowed to become multiline if needed.

FLEX-WRAP
Values: nowrap | wrap | wrap-reverse
Default value: nowrap

To understand better, by default, no matter how many flex items there are inside the flex container, all the flex items will appear on a single line. This is something which it is not needed in all situations. That is why we need flex-wrap. When wrap or wrap-reverse are used, the flex items will wrap onto additional flex lines when the constraints of the parent flex container are reached.

When flex-wrap is set to wrap-reverse and flex-direction is set to row or row-reverse, the cross start and cross end directions are swapped, with the cross start on the bottom, cross end on top, and the cross axis going from bottom to top. Remember that normally for flex-direction of row and row-reverse, the cross-axis goes from top to bottom, with the cross-start on top and cross-end on the bottom. So, again, for wrap-reverse, in this case, the cross-axis goes from bottom to top.

When flex-wrap is set to wrap-reverse and flex-direction is set to column or column-reverse, the cross axis is inverted, with cross start being on the right, cross end being on the left, the cross axis going from right to left, with additional flex lines being added to the left of the previously drawn line. Remember that when flex-direction is set to column or column-reverse, by default the cross axis goes from left to right in left-to-right languages, with new flex lines being added to the right of previous lines. So, again, for wrap-reverse, in this case, the cross-axis goes from right to left.

The flex-flow shorthand property

This is actually a combination between flex-direction and flex-wrap. So it defines the directions of the two axes (main and cross) and also the wrapping behavior.

FLEX-FLOW
Values: values of flex-direction || values of flex-wrap
Default value: row nowrap

So when you declare an element with this property flex-flow: column wrap; it is exactly the same thing as you would declare flex-direction: column; flex-wrap: wrap;.

The justify-content property

This property controls how flex items in a flex line are distributed along the main axis while the align-content property (which we will discuss shortly) defines how flex lines are distributed along the cross axis of the flex container. The align-items property (which we will also discuss shortly) defines how flex items are aligned along its flex line's cross axis.

JUSTIFY-CONTENT
Values: flex-start | flex-end | center | space-between | space-around | space-evenly | initial | inherit
Default value: flex-start

As you noticed the above examples happen when flex-direction is set to row. When flex-direction is set to column, the flex items behave the same, but vertically. There are other situations which can be discussed regarding justify-content (like when flex items overflow the flex container when flex-wrap is set to nowrap), but we will stick with the most common cases.

Hopefully the differences between space-between, space-around and space-evenly are clear.

For space-between, items have space between them while for space-around items have equal space to their left and right (for example A has equal space on left and right and then B has equal space on left and right too; as a result, the space between A and B is double of the space on the left of A).

Space-evenly adds equal space around the flex items (so space from the left of the flex container to A is equal to the space between A and B).

Initial sets this property to its default value and inherit means that it inherits this property from its parent element.

The align-items property

This property defines how flex items are aligned along its flex line's cross-axis.

ALIGN-ITEMS
Values: flex-start | flex-end | center | baseline | stretch | initial | inherit
Default value: stretch

The above images should be clear. One confusing issue could be the align-items:baseline, which means that the flex items in each line are all aligned at their baselines, which is actually the bottom of the first line of text.

The align-content property

This property only impacts flex line alignment in multiline flex containers. The align-content property aligns a flex container's lines within a flex container that has extra space in the cross-axis direction, and dictates which direction will have overflow when there is not enough room to fit the flex lines.

Unlike justify-content which aligns individual items along the main-axis of the flex container, the align-content property aligns flex lines across the cross-axis of the container. This property only applies to flex containers which have multiple lines.

ALIGN-CONTENT
Values: flex-start | flex-end | center | space-between | space-around | stretch | space-evenly | initial | inherit
Default value: stretch

Flex items properties

We have discussed above the properties applicable to the flex container, and now we will take a look at the properties applicable to the flex items. These properties allow us to precisely control the layout of individual non-anonymous flex items. When there are text-node children of flex containers, if the text node is not empty (containing content other than whitespace) it will be wrapped in anononymous flex item, behaving like the other flex items. These text nodes are the anonymous flex items and it is not possible to directly set any of the flex items properties on them.

The normal float and clear properties don't have an effect on flex items, while absolute positioning elements are taken out of the flow of the document, but they do not get converted to flex items and they are not in the document flow. To be more clear, if we set align-content: center; on the absolutely positioned child, it will by default be centered on the flex container parent's cross-axis.

Before discussing about flex-grow, flex-shrink, and flex-basis properties we need to understand that it is always recommended to use the flex shorthand property which contains all three properties.

So we will discuss about each one, to have a better understanding, and then we will discuss about the flex shorthand property which it is the one which we always need to use.

The flex-grow property

This property defines how much a flex item will grow proportionally relative to the growth of other flex item siblings, if it is allowed to grow and if there is available free space.

FLEX-GROW
Values: number (negative numbers are not valid; float values, as long as they are greater than 0, are valid)
Default value: 0

The value specifies the growth factor, which determines how much the flex item will grow relative to the rest of the flex item siblings as the flex container's free space is distributed. If there is any available space within the flex container, the space will be distributed proportionally among the flex items with a nonzero positive growth factor based on the various values of those growth factors.

Let's have a few examples to understand better.

We have a flex container with a declared width of 600px and inside this container we have threee flex items. Each flex item has a declared value of 100px.

If we set flex-grox: 0 to each of the flex items, there are no growth factors set, so no flex items grew. The three flex items will have 300px total width (3*100px) and the free space will be 300px (600px-300px).

Let's have another example.

As you can see in the below picture, the first two fles items have flex-grow: 0 and the third one has a flex-grow: 1. In this case, since there is only one growth factor, the third item will take all the free space of the flex container. So the width of the third item will be the item width (which it is 100px) plus the free space width (which it is 300px). In other words, since only one flex item has a nonzero growth factor, this flex item will take all the available free space which will be added to its declared width. Actually, if this growth factor was 0.1 or 9999, the width of the third flex item would have been the same.

In the third example, all three items are allowed to grow, the free space is distributed proportionally based on the flex growth factors. With two flex items having a growth factor of 1, and one flex item having a growth factor of 3, we have a total of five growth factors: (2 x 1) + (1 x 3) = 5.

With 5 growth factors, and a total of 450 px needing to be distributed, each growth factor is worth 90 px: 300px / 5 = 60px.

Before being allowed to grow based on individual flex item's growth factor, the flex items were each 100 px wide. With each growth factor being 60 px, we have 2 flex items with a width of 160 px each and the last flex item has a width of 370 px: 100px + (1 x 60px) = 160px ; 100px + (3 x 60px) = 280px.

The flex-shrink property

This property defines how much a flex item will shrink relative to the other flex item siblings when there isn't enough space for them all to fit in the flex container.

FLEX-SHRINK
Values: number (negative numbers are not valid; float values, as long as they are greater than 0, are valid)
Default value: 1

The value specifies the shrink factor.

Again, let's have a few examples to understand better.

We have a flex container with a declared width of 600px and inside this container we have threee flex items. Each flex item has a declared value of 250px.

If we set flex-shrink: 0 to each of the flex items, there are no shrink factors set, so no flex items shrink. The three flex items will have 750px total width (3*250px) and the overflow (or the negative space) will be 150px (750px-600px).

The second example.

As you can see in the below picture, the first two fles items have flex-shrink: 0 and the third one has a flex-shrink: 1. In this case, since thrre is only one shrink factor, the third item will take all the free space of the flex container. So the width of the third item will be the item width (which it is 250px) minus the overflow width (which it is 150px). So the width of the third flex item will be 100px. In other words, since only one flex item has a nonzero shrink factor, this flex item will have its width reduced with all the overflow width. Actually, if this shrink factor was 0.1 or 9999, the width of the third flex item would have been the same.

In the third example, all three items can shrink, because their shrink factor is greater than 0. With two flex items having a shrink factor of 1, and one flex item having a shrink factor of 3, we have a total of five shrink factors: (2 x 1) + (1 x 3) = 5.

With 5 shrink factors, and a total of 150 px overflow, each shrink factor is worth 30 px: 150px / 5 = 30px.

Before the shrink, the flex items were each 250 px wide. With each shrink factor being 30 px, we have 2 flex items with a width of 220 px each and the last flex item has a width of 160 px: 250px - (1 x 30px) = 220px ; 250px - (3 x 30px) = 160px.

As you have noticed, in the above examples the flex items have the same width. When we have flex items with differet widths, then we need to calculate the shrink percent.

The formula is Shrink Percent = Negative Space/ ((Width1 _ ShrinkFactor1) + (Width2 _ ShrinkFactor2) + (Width3 * ShrinkFactor3)). Then we will reduce each flex item by shrink percent.

The flex-basis property

FLEX-BASIS
Values: content | width
Default value: auto

The flex-basis component of the flex property defines the initial or default size of flex items, before extra or negative space is distributed - before the flex items are allowed to grow or shrink according to their growth and shrink factors, which we discussed above.

Flex-basis overrules any specified CSS width/height value.

In the below example we have three flex items which have different widths declared, but they are overruled by the flex-basis.

There are many things and situations which we could discuss about the flex-basis property, but we will just stick with the basic explanation for now.

The flex shorthand property

The flex shorthand, a flex item property, is made up of the flex-grow, flex-shrink, and flex-basis properties, which define the flex growth factor, the flex shrink factor, and the flex basis, respectively.

FLEX
Values: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
Default value: flex-grow: 1; flex-shrink: 1; flex-basis: 0%;

The flex property may be specified using one, two, or three values.

  1. One-value syntax: the value must be one of:
  • a number: In this case it is interpreted as flex: number 1 0; the flex-shrink value is assumed to be 1 and the flex-basis value is assumed to be 0.
  • a width: In this case it is interpreted as flex: 1 1 width; the flex-grow value is assumed to be 1 and the flex-shrink value is assumed to be 1.
  • one of the keywords: none, auto, or initial.

a. none The item is sized according to its width and height properties. It is fully inflexible: it neither shrinks nor grows in relation to the flex container. This is equivalent to setting flex: 0 0 auto;.

b. auto The item is sized according to its width and height properties, but grows to absorb any extra free space in the flex container, and shrinks to its minimum size to fit the container. This is equivalent to setting flex: 1 1 auto;.

c. initial The item is sized according to its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container. This is equivalent to setting flex: 0 1 auto;.

  1. Two-value syntax:
  • The first value must be:
    -- a number and it is interpreted as flex-grow.
  • The second value must be one of:
    -- a number: then it is interpreted as flex-shrink.
    -- a valid value for width: then it is interpreted as flex-basis.
  1. Three-value syntax: the values must be in the following order:

    -- a number for flex-grow.
    -- a number for flex-shrink.
    -- a valid value for width for flex-basis.

The align-self property

This property is used to override the align-items property value on a per-flex-item basis.

As we discussed, the align-items property set on the flex container allows us to align all the flex items of that container to the start, end, or center of the cross-axis of their flex line. The align-self property, which is set directly on the flex item, enables us to override the aligns-items property on a per-flex-item basis.

In the below example, the second flex item (the B's) is aligned to the flex-end.

The order property

As we already know, flex items are, by default, displayed and laid out in the same order as they appear in the source code. The order of flex items and flex lines can be reversed with flex container property reverse values which we have discussed above. The order property can be used to change the ordering of individual flex items.

By default, all flex items are assigned the order of 0, with the flex items being displayed in the same order as the source order and the direction of that order based on the flex container properties.

ORDER
Values: integer
Default value: 0

Negative values are accepted.

In the below example, the 4th flex item has a negative value and it will appear before the other flex items with order 0. The 5th flex item has order: 1 and it appears after all the other flex items.

Conclusion

CSS flexbox it's really great and it can be used to create complex layouts with very little code. Having a really deep understanding of CSS flexbox, which I hope that this article can provide, it is a big step forward in your web design career.

Comments closed

Please contact me, if you have any questions or suggestions.