CSS has helped developers create many different kinds of web page layouts. One challenge web developers often face is positioning different content parts on a web page. Flexbox makes this task easy and predictable across different screen sizes.
This course will cover all the fundamental and advanced concepts you need to get good with the CSS Flexbox model. You will learn to layout a Responsive Music App in the process. It is a detailed course, and I hope you’re ready for it.
Today we'll introduce some basics of Flexbox to help you get started with it.
Imagine creating a web page with three distinct sections in it. You might have the following code:
We define a top-level div
element and nest three div
elements inside it.
Why do each of the three div
elements appear on separate "lines"? This is because they're block elements, and the default CSS layout mode is in effect: namely, flow mode.
Flow mode is useful for documents, which is what the world wide web was originally for. Words are displayed next to each other in a line, from left to right (for the English language), then begin to wrap around on the next line when there’s no more space on the current line. Block-level elements (like p
and div
) on the other hand, are put on separate lines. The three children div
elements, being block elements, occupy the width of their parent div
element and are stacked on top of each other in separate rows.
Switching to the Flexbox layout mode provides lots of flexibility in element layouts. Central to a Flexbox-based layout is an HTML element that serves as the Flexbox container. This element contains one (usually two) or more other elements that are termed children. The idea is to control the positioning of the children within the container. We declare an HTML element as a Flexbox container by specifying display: flex;
in its style. We then set some Flexbox properties to help us achieve the desired layout.
In the above coding playground, uncomment line 26 in the CSS file and see what happens. We configure the top-level div
element as a Flexbox container (line 26 in CSS) and nest three div
elements inside it. This change enables the Flexbox layout mode, which, by default, lays out the children one after the other at the start of a row.
The following illustration shows how the parent-child DOM element relationship (CSS not shown for simplicity) translates to the Flex container layout.
CSS Flexbox layout mode has a main axis and a cross axis. The children are distributed within the container element along the main axis. By default, the main axis is horizontal, which is why children are laid out horizontally from left to right. To change the children’s orientation within the container, we need to switch the main and cross axes. We do this with the flex-direction
property on the container element. The default value is row
, but we can change it to row-reverse
, column
, or column-reverse
. To see the effect, try changing that property using the “Row”, “Row Reverse”, “Column” and “Column Reverse” buttons in the following playground. Clicking these buttons sets the flex-direction
property on the container element to the appropriate value. You can use the checkbox at the bottom of the playground to indicate the main axis.
For the rest of the blog, we use only Row and Column as the available options, in the interest of simplicity and brevity.
We have the following markup:
<nav class="navigation">
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
The class named container
is a Flex container. We want the list items to be arranged from left to right. Which CSS selector achieves this?
.navigation { flex-direction: column; }
.navigation { flex-direction: row; }
.navigation { flex-direction: row-reverse; }
.navigation { flex-direction: column-reverse; }
To control the distribution of children along the main axis, use the justify-content
property on the container element. The following coding playground shows all the possible values for this property. See what each value for this property achieves.
We are designing a navigation bar where we want the menu items to be evenly distributed across the container. Which value do we set for the justify-content
property?
flex-start
flex-end
center
space-between
If different children have different dimensions, for example, div
elements with different amounts of text, shouldn’t there be options to control where the children are positioned along the cross axis? That’s where the align-items
property comes in. It is applied to the container element, but applies the alignment to all the direct children. Try playing with this property’s values in the following playground where each child element has a different dimension.
There are other possible values for the align-items
property. Please see the Mozilla documentation for details.
There’s also the align-self
property that has the same set of available values as the align-items
property. It can be applied to a child element to override the setting of the align-items
property set on the container element. Use this when you want to align one (or a few) children differently from the other children. In the following playground, the “Home” and “About” children are positioned through the align-items
property on the flex container, whereas the “Products” element is positioned using align-self
.
Suppose you’re working on a layout with a sidebar containing multiple sections. You want the “news” section to be aligned at the bottom of the sidebar while the others remain aligned at the top. Which property would you apply to the “news” section?
justify-contents
align-items
align-self
justify-self
The properties that we’ve just seen aren’t arbitrarily named. Think of content as the term used for whatever group of elements we have along the main axis. On the other hand, think of items as the term for whatever element(s) we have along the cross axis. Furthermore, the term justify deals with the placement along the main axis, whereas align deals with the placement along the cross axis. All of the Flexbox children are cut across by the main axis, but each child has its own separate cross axis. That’s why the justify-content
property value gets applied to the group of children together, while the align-items
property applies individually to each child. For instance, if align-items
is set to center
, each child is centered on the cross axis according to its own dimensions.
Flex flow mode tries to fit all child elements into a single row inside the flex container. It will shrink the children if needed and if possible. However, sometimes we want the remaining child elements to wrap over to the next row. In such cases, we can set the flex-wrap
property to wrap
on the container element. The default value for this property is nowrap
. Another possible value is wrap-reverse
. Let's see this property in action.
In the following playground, we have a flex container of 400 pixels by 400 pixels. The “Home” and “Products” elements are 150 pixels by 150 pixels. With the flex-wrap
property set to nowrap
and flex-direction
set to column
, the Flex layout mode fits the three elements in the same column. It turns out the absolute height
(or width
) specified for children are suggestions and not hard constraints for the Flex layout mode. When you set the flex-wrap
property to wrap
, you see wrapping in action. With flex-wrap
set to wrap-reverse
, the placement and wrapping is done in a direction opposite to the usual direction of the main axis.
We usually control the space between elements using the margin-*
properties. Imagine the links in a horizontal navigation bar. We might want the first and the last links to be left-aligned and right-aligned, respectively, with an equal space between elements everywhere else. For something like this without Flexbox, we have to resort to some fancy selectors. Flexbox provides an easy way to achieve this spacing using the gap
, row-gap
, and column-gap
properties on the container element.
In the following playground, we gave the flex container element and the children fixed dimensions. Choose the property you want to modify and change its value using the slider to see the effect.
Let's say we are creating a horizontal navigation bar. We might start with the following.
With just the short CSS above, we apply a few flex properties to each of the children and get their default values, resulting in a reasonable display. Let's discuss these properties.
Note that these properties can be assigned individually to each child.
We can size HTML elements using the width
and height
properties (among others). But what if you wanted to set the dimension of a child element along the main axis? Do you set the width
or the height
? The answer depends on the value of the flex-direction
property, right? Flexbox provides a property named flex-basis
which refers to the dimension of a particular child along the main axis.
Let's say we have a three-column layout of a page: a vertical navigation bar on the left, main content in the center, and some useful links to the right. We set the flex-basis
property on the left and right columns to 10% each. You can vary the flex-basis
property for the main content column using the slider. Notice how flex-basis
is also a suggested starting size of the child elements and not a hard constraint. Flexbox distributes the available space among the children reasonably.
Flexbox distributes space available in the container element among the children, the space between them, and the space around them. The flex-grow
property, set on the child elements, represents whether the child should grow to accept space distributed by Flex layout or not. The default value for this property is 0, i.e., do not grow. This isn't a 0/1-valued property. You can set it to any non-negative number. Flexbox distributes the total space available in the container among the children in the proportion of values of their flex-grow
properties. Let’s look at an example to explain that.
If we want to size some children equally and some other(s) proportionately bigger, we can set flex-grow
to 1 on the former set of elements, and set it to 2, or 3, or whatever fraction we desire on the latter set of elements. In the following playground, we have a website with a horizontal navigation bar on top and a two-column layout in the main section. The main content is to the left, and there’s a “What’s new!” section on the right. We set the flex-grow
property to 1 on both the main content and the “What’s new!” section. That’s why they are sized almost equally. But you can use the slider to change the value of the flex-grow
property on the main content to see the effect.
Another thing that Flexbox does is that it causes children to shrink compared to their assigned width
or height
property. This is the effect of the flex-shrink
property, set on the child elements, with the default value being 1, i.e., do shrink.
In the following playground, we've given each button a width
of 1000 pixels, which can clearly not be accommodated in the flex container. Yet, we don't see a horizontal scroll bar. The reason is the default value of the flex-shrink
property. This is because Flexbox shrinks all the children until they have equal width. That’s why, despite the justify-content
property set to space-between
, the “Contact Us” button is not flush with the right edge, unlike the previous playground.
We are developing a dashboard with resizable widgets. We want each widget to shrink when the available space decreases, but we want to prevent one specific widget from shrinking beyond a certain point. Which value should we assign to the flex-shrink property for that specific widget?
0
1
2
auto
This is a shorthand property to set flex-grow
, flex-shrink
, and flex-basis
all in one line. This property is also set on a child element. We may skip the last two values when configuring this property. In this case, flex-basis
is implicitly set to 0. We may skip the value for the flex-shrink
property by setting this property to two values, with the second value being a length value such as 10px
rather than just a number. Skipping the value for flex-basis
is straightforward.
We hope that this blog helped you learn a thing or two about CSS Flexbox!
To refresh your memory, here's a table summarizing the properties that we discussed today.
Property | Set on | Purpose |
| Container | Indicates that the children of this element should be placed according to the Flex layout mode. |
| Container | The orientation of the main axis. The default value is |
| Container | Configures the distribution of children along the main axis. |
| Container | Configures the distribution of children along the cross axis. |
| Child | Configures the placement of a particular child element on the cross axis. |
| Container | Configures whether items should wrap over to the next row (or column) if they can’t all fit in the current one. |
| Container | Configures the gap between two consecutive rows. This property can have any length unit. |
| Container | Configures the gap between two consecutive columns. This property can have any length unit. |
| Container | Configures the gap between two consecutive rows and consecutive columns. This property can have any length unit. |
| Child | Configures the starting minimum size of a child element along the main axis before the Flex layout distributes container space among the children. |
| Child | Configures the behavior of a child element in case Flex layout has to grow the children to occupy the available container space. Space is distributed among the children in proportion of the value of this property. |
| Child | Configures the behavior of a child element in case Flex layout has to shrink the children to fit within the available container space. The children shrink in proportion of the value of this property. |
You can continue getting hands-on with Flexbox in some of our courses below:
Free Resources