Overview of This Lesson

Before responsive design, we often had to create page layouts using CSS Positioning properties. Laying out a page with those properties can be hard to learn, and difficult to use for complex layouts, and they are generally very difficult to make responsive. CSS Flexbox was added to the CSS specification in 2009 and the CSS Responsive Grid was added in 2011; both of these allow you to create responsive web pages. When added with media queries, you can create complex, accessible, responsive page layouts.

Pre-Requisites

Make sure that you've worked through the previous tutorial, Responsive Design tutorial before proceeding through this lesson.

A Basic Flexbox

The CSS FlexBox properties make creating simple, accessible layouts easy. Using FlexBox, you can create a basic single-column or single-row layout that is responsive. You can even nest flexbox containers inside other flexbox containers, for more interesting layout affects that are still accessible.

To use a flex box layout, follow these steps:

  1. Define a flex container
  2. Define the behaviour of your flex container
    • Determine general layout of flex items
    • Determine general alignment of flex items
  3. Customize behaviour of individual flex items, if necessary

Define a Flex Container

A flex container is the main parent or container for all of the other elements you want to lay out. This parent/container element must have the display property set to flex.

main {
  display: flex;
}

The example above creates a rule that makes <main> element a flex box.

If you'd like to create a flex box and learn as you go, you can use this Flex Box Starter codepen:

See the Pen Flex Box Starter by Wendi Jollymore (@ProfWendi) on CodePen.

In this Codepen example, the outer DIV will be the flex container and the inner DIVs will be the flex items.

If you're using the Codepen (or you can copy the contents of the HTML and CSS tabs to your own project), go ahead and change the .flex-box rule by adding display: flex;. Then check to see how the layout of your page changes.

Once you add display: flex; to the main .flex-box container, you'll notice that all the inner DIV elements with the green border change size and position: previously each DIV took up the full width of the screen (which is the default behaviour for block elements) and were stacked on top of each other. After making the outer div a flex box, the DIVs resize to fit their contents, and they are laid out horizontally. Depending on your screen width, they may overflow the outer div container.

By default, a flex box lays out all its flex items in a non-wrapping row: all items will be placed horizontally next to each other, and if there are more items than the flex container will fit, they will overflow the container. In the next few sections we'll see how to change how change our flexbox to a column layout, and also how to tell flex items to wrap to the next row/column instead of overflowing the container.

Customizing Flexbox Layout

Once you add display: flex; to your container rule, you can define other CSS properties that affect the behaviour of your flex container. For example, you can change the direction of your layout to be horizontal (row, which as you saw is the default) or vertical (column) You can also define how you want items in your flex container to wrap when the container is not wide or tall enough.

Layout: flex-direction

The flex-direction property defines how you wish to lay out the items inside your flex container. You can give it one of the following values:

In the Codepen from earlier, try adding:

flex-direction: column;

Try the other values also: see how row-reverse and column-reverse work. Notice also that with some options, the alignment of items might also change!

Wrapping Items: flex-wrap

The flex-wrap property defines whether or not the items in the container should wrap to, the next row/column, how they should wrap. You can use the following values:

Try this in the earlier CodePen example: set the following properties on your flex container:

display: flex;
flex-direction: row;
flex-wrap: wrap;

Make sure you resize your viewport so you can see the effects of wrapping.

Here's a CodePen that demonstrates a version of the earlier CodePen but with columns (I achieved this by setting the height of the outer DIV to half the viewport height).

See the Pen Flex Box Starter by Wendi Jollymore (@ProfWendi) on CodePen.

Shorthand Property: flex-flow

The flex-flow property is actually a shorthand property for the combination of flex-direction and flex-wrap. Specify a direction property value first, then a wrap property value. For example, to set flex-direction to column and flex-wrap to "wrap":

flex-flow: column wrap;

Try it out with the following CodePen. I left you some instructions and suggestions, along with some things to try.

See the Pen Flex: Intro, Flex Flow by Wendi Jollymore (@ProfWendi) on CodePen.

Flexbox Item Alignment

You might have noticed after playing with the previous CodePen example that some strange things occur when you try certain combinations of property values. For example, when you set the flex box container's height to a large value such as 1000 pixels while the flex box is a wrapping row, you end up with a large amount of space between the wrapped rows. You can customize this behaviour by setting various alignment properties.

There are three general things you can align in a flex box:

The main axis or inline axis refers to the axis that the flex lines are on. For row layouts, your main axis would be horizontal. For column layouts, your main axis would be vertical.

The cross axis or block axis refers to the axis that isn't the main axis. For row layouts, your main axis is horizontal, so your cross axis is vertical. For column layouts, your main axis is vertical, so your cross axis is horizontal.

Therefore, alignment on the main axis and cross axis depends on whether you're using a row layout or column layout for your flex container.

Additionally, when it eventually comes to sizing items, it's important to understand the main size: the main size is the size of the item's dimension on the main axis. You can probably guess that you will also occasionally refer to an item's cross size, which is the size of the item's dimension on the cross axis.

Row Layout: alignment within the main axis refers to how items are collectively aligned horizontally along the row: are they all clustered at the left end of the row, right end of the row, or are they all centered on the row? Alignment of items within the cross axis refers to how the items are aligned vertically in the row: do they sit with their tops flush to the top of the row, centered in the row, or with their bottoms flush to the bottom of the row?

The main size of a flex item in a row layout is the item's width, since the flex items are aligned on the main axis horizontally.

the main axis in a row layout is horizontal
The main axis in a row layout flex box is horizontal. The cross axis in a row layout is vertical. The "main size" refers to the width of flex box items.

Column Layout: Alignment within the main axis refers to the vertical alignment of the collection of items within the column: are all the items clustered together at the top of the column, bottom of the column, or are they centered vertically in the column? Alignment within the cross axis refers to the horizontal alignment of the collection of items within the column (e.g. are they clustered together at the right side or left side of the column, or are they centered horizontally within the column?)

The main size of a flex item in a column layout is the item's height, since the flex items are aligned on the main axis vertically.

the main axis in a column layout is vertical
The main axis in a column layout flex box is vertical. The cross axis in a column layout is horizontal. The "main size" refers to the height of flex box items.

The flex line, refers to imaginary lines that run along the main axis. For row layouts, flex lines are like shelves that the items sit on. Alignment of these flex lines define where the "shelves" sit on the page: should the flex lines appear at the top of the page or at the bottom, or perhaps in the middle? For column layouts, the flex lines are vertical (imagine shelves, but turn the wall sideways). Alignment of these flex lines define where the columns go on the page: maybe all to the left side, all to the right side, or right down the center?

flex lines in a row layout
In a row layout flex box, the flex lines run horizontally.

flex lines in a column layout
In a column layout flex box, the flex lines run vertically.

It may be hard to imagine these details, so we'll look at each of the three properties and try lots of examples.

Main Axis Alignment: justify-content

When the flex container items don't use up all the space available, on the main axis, the justify-content property defines how those items should use up that available space. You can use any of the following values:

Play with the justify-content property using the CodePen below. Make sure you try all the values for both row layout and column layout.

See the Pen Flex: Justify Content by Wendi Jollymore (@ProfWendi) on CodePen.

Cross Axis Alignment: align-items

The align-items property aligns the items on the cross axis. You can assign this property one of the following values:

Play with the align-items property using the CodePen below. Make sure you try all the values for both row layout and column layout.

See the Pen Flex: Align Items by Wendi Jollymore (@ProfWendi) on CodePen.

Flex Line Alignment: align-content

Where the properties justify-content and align-items align the collections of items in the flex container, the align-content property defines how to align the flex lines of the container. A flex line is the row or line that the items inside a flex box sit on. In a horizontal flex box, the flex line is the imaginary horizontal line that makes up a row of items. In a vertical flex box, the flex line is the imaginary vertical line that makes up a column of items.

For a horizontal row flex box, think of the flex line as the shelf that you might place some flex item ornaments on. Flex line alignment determines how those shelves are aligned on the wall: are the shelves up near the top of the wall, near the middle of the wall, or close to the bottom of the wall?

For a vertical column flex box, think of the flex lines as a bunch of strings that you have hanging from the ceiling that you might hang decorations on (like holiday cards or paper ornaments). Are you going to hang a set of strings on one side of the wall, or are you going to cluster them all in the middle of the wall?

Don't worry if you're not getting it right away: the examples coming up should make it very clear.

The align-content property can have the following values:

Play with the align-content property using the CodePen below. Make sure you try all the values for both row layout and column layout.

See the Pen Flex: Align Content by Wendi Jollymore (@ProfWendi) on CodePen.

CodePen: Flex Box Alignment

This CodePen allows you to play with all three alignment properties at once. This one is better if you open it in its own window and lay out the code windows on the side.

See the Pen Flex: Alignment by Wendi Jollymore (@ProfWendi) on CodePen.

Customizing Flex Items

The individual items inside your flex box are called flex items. All the flex box properties you've learned so far define the defaults for all flex items: the default alignment, default layout, etc. You can customize various behaviours for individual items that don't follow the defaults you've already defined. For example, you might have set the alignment of all your grid items to be vertically centered, but you might wish to change one or two items to be aligned differently. This can be done by changing properties of those individual flex items.

Default Size of Flex Items: flex-basis

The flex-basis property defines the default main size of a flex item before it is placed into the flex container. Recall that by "main size" we're referring to either the width for row layouts, or the height for column layouts.

It's possible that a flex container might be too big or too small to fit the flex items, so the items might grow or shrink from their original flex-basis once they're put into the container. The value of flex-basis can be any valid size unit or percentage, or it can be one of several keyword values:

Experiment with flex-basis and answer the question in the CodePen:

See the Pen Flex Items: flex-basis by Wendi Jollymore (@ProfWendi) on CodePen.

Size of Flex Items: flex-grow

The flex-grow property defines how much a flex item should grow (if it is allowed to grow at all) in relation to the other items in the container. The value of flex-grow is a number N, which represents N times more than an item with a value of 1. The default is 0, which means the item doesn't grow at all.

Try the demonstrations in the CodePen below, the instructions are in the CSS tab:

See the Pen Flex Items: Grow by Wendi Jollymore (@ProfWendi) on CodePen.

In the first Demo, after you uncomment the .flexbox div:first-child rule, you'll notice that the "1" box takes up any space that is not taken by the rest of the boxes. Setting flex-grow to 1 tells the flex item to grow as much as it's allowed, because all the other items have a default flex-grow of 0.

In the second Demo, you can see that when all flex items have a flex-grow of 1, it means they should ALL take up whatever space is available, causing them all to have equal widths. When the "1" box has its flex-grow set to 2, that means it has been given permission to grow take up twice as much of the remaining space as the other flex items are allowed to have.

Since there are 800px available, and since one item has flex-grow: 2 and the other four have flex-grow: 1, that means the available space is divided up into 6 equal parts (2 + 1 + 1 + 1 + 1). That means each part is 800/6 = 133.33 pixels. So the items with flex-grow: 1 get 133.3px each, and then item with flex-grow: 2 gets 2 * 133.3px = 266.6px.

Practice the math: say you have 1000px available in a row and you have 3 flex items with flex-grow: 1, two flex items with flex-grow: 2, and one flex-item with flex-grow: 3, how many pixels are allocated to each flex item?

Solution:
Number of "parts": 3 * 1 + 2 * 2 + 3 = 10
Total space is 1000px, divided into 10 parts:
1000 / 10 = 100, so 100px for each "part"
Therefore:
The flex-grow: 1 items get 100px each
The flex-grow: 2 items get 200px each
The flex-grow: 3 item gets 300px
Check:
3 + 100 + 2 * 200 + 300 = 300 + 400 + 300 = 1000

Size of Flex Items: flex-shrink

The flex-shrink property defines how much flex items should shrink in comparison with other flex items in the container. The property works similarly to flex-grow, taking a numeric value representing a shrink factor, although the default value for flex-shrink is 1, instead of 0.

Try the demonstrations in the CodePen below, the instructions are in the CSS tab:

See the Pen Flex Items: Shrink by Wendi Jollymore (@ProfWendi) on CodePen.

In the first demo, all the flex items have a flex-shrink of 1 (all shrink equally) and the first item (the "1" box) has a flex-shrink of 2: this makes the first item shrink more. When you look at all the flex-shrink values, there are 6 parts: 2 + 1 + 1 + 1 + 1 = 6. Each of the five items has a flex-basis of 200px, but 200 pixels too much to fit a flex container that is 800px wide. We actually need 1000px of space (200px * 5 items), a difference of 200px. To make them all fit equally, we have to remove 200 pixels equally: each one should have 160 pixels of space (800px / 5). So each item should take up 40 fewer pixels. However, one of the items has a flex-shrink of 2: this means it has to shrink twice as much as the others. So that means we have 6 "parts", and each "part" is 200/6 = 33.33 pixels. So items with flex-shrink: 1 shrink by 33.3 pixels, items with flex-shrink: 2 shrink by 66.66 pixels.

In the second demo, all items have a flex-shrink of 1, except the "1" box, which is set to 0. This means all items will shrink equally except for the first div, which will keep it's preferred size: the flex-basis value of 200px. This means that there is 600px available for the other 4 flex items, so each one gets 600/4 = 150px.

Shorthand Flex Property

The flex property is a shorthand property for flex-grow, flex-shrink, and flex-basis.

The flex property can take one, two, or three values, as follows:

See the Pen Flex Items: flex shorthand by Wendi Jollymore (@ProfWendi) on CodePen.

Flex Item Alignmment: align-self

The align-self property overrides the align-items property of the flex container for an individual item, allowing you to align individual flex items differently than the rest of the items in a container. For row layouts, this changes the vertical alignment of the item in its row. For column layouts, this changes the horizontal alignment of them item within its column. Possible values for the align-self property are:

See the Pen Flex Items: align-self by Wendi Jollymore (@ProfWendi) on CodePen.

Exercises

1. The instructions are in the CodePen:

See the Pen Flex: Exercise 1 by Wendi Jollymore (@ProfWendi) on CodePen.

(Exercise 1 Solution)

2. The instructions are in the CodePen:

See the Pen Flexbox Exercise 2b (solution) by Wendi Jollymore (@ProfWendi) on CodePen.

(Exercise 2 solution)