Flexbox in 10 minutes
Flexbox has emerged as the best way to create HTML layouts. Consider the HTML example below, where we have a div element with a class of container. This element contains three inner div elements, with the classes item1, item2, and item3.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS by example</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
</body>
</html>
Next, we write CSS rules to apply styling to the container and item elements. We give the outer div a width of 600 pixels and light gray background using hex code #eee. The item elements are different colors and also have different height and width properties.
.container {
width: 600px;
background-color: #eee;
}
.item1 {
width: 150px;
height: 100px;
background-color: magenta;
}
.item2 {
width: 75px;
height: 75px;
background-color: yellow;
}
.item3 {
width: 100px;
height: 150px;
background-color: cyan;
}
By default, the div elements will all be displayed as block elements. This means that each inner div element will be drawn under the previous one. Effectively they each occupy a whole row of space in the layout.
Here is the result rendered in a web browser:
We can use a flexbox layout by setting the display property of the container div element to be flex.
.container {
width: 600px;
background-color: #eee;
display: flex;
}
The layout is completely different. By default, flexbox will display items in a row.
This is incredibly useful for arranging a row of items, such as navigation links on a horizontal menu. By setting additional CSS properties, we can alter the behavior of flexbox to create almost any layout.
The ‘justify-content’ property
The key to understanding flexbox is to imagine an arrow pointing horizontally in the direction of the row. We can set the justify-content property to specify how the items should be spaced out along that row. For example, we could set justify-content to center.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: center;
}
As we might expect, our items are now positioned in the center of the container space.
Alternatively, we could set the justify-content property to space-between.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: space-between;
}
This time, our items are spread across the horizontal space with even spacing between them. The first item, in magenta, is flush against the start of the container on the left. The last item, in cyan, is flush against the end of the container on the right:
Another way to space out items would be to set justify-content to space-evenly. In this case, we also include the same amount of spacing before the first item and after the last item.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: space-evenly;
}
Here is the resulting layout:
We could also set justify-content to space-around. This is another variation where we use a full space between each item, and a half space at the start and end of the flexbox.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: space-around;
}
This time, note how the first item, in magenta, is closer to the start of the flexbox, and the last item, in cyan, is closer to the end.
Another option would be to set justify-content to flex-start.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: flex-start;
}
Finally, we can set the justify-content property to flex-end.
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: flex-end;
}
If we check the new layout, sure enough, the items are now arranged at the end of the flexbox on the right-hand side:
The ‘flex-direction’ property
The flexbox can be customized in many ways, allowing it to be applied to almost any layout we might have in mind. An important property available is the flex-direction property. The default value is row, but we could also set this to row-reverse.
.container {
width: 600px;
background-color: #eee;
display: flex;
flex-direction: row-reverse;
}
In the resulting layout, our inner HTML items are arranged in a row in reverse order. We see the first element, in magenta, drawn on the right-hand side. The last element, in cyan, is now drawn on the left-hand side:
With a flex-direction of row-reverse, the start of the container is now considered to be on the right-hand side of the row. We can visualize an arrow going from the right of the container to the left. The first item, in magenta, is drawn at the start of the container, which now happens to be on the right-hand side.
What would happen if we set the justify-content property to flex-end?
.container {
width: 600px;
background-color: #eee;
display: flex;
justify-content: flex-end;
flex-direction: row-reverse;
}
With a flex-direction of row-reverse, the end of the container is considered to be the left-hand side. We would expect the items to be placed on the left of the container. Here is the result:
The row-reverse option is particularly useful for responsive layouts, where we might want our items arranged in one direction for mobile view and another direction on a larger screen.
Flexbox as a column
Flexbox offers two more options for the flex-direction, column, and column-reverse. Let’s try setting the flex-direction property to column. To make things clearer we also set a container height property of 500 pixels.
.container {
width: 600px;
height: 500px;
background-color: #eee;
display: flex;
flex-direction: column;
}
We can visualize an arrow pointing from the top of the container, considered the start, down to the bottom of the container, considered the end. By default, our items are arranged in a column starting at the top:
What would happen if we set the flex-direction property to column-reverse? This time we can visualize an arrow pointing from the bottom of the container up to the top. Our items will be arranged in a column, starting from the bottom.
The ‘align-items’ property
Now let’s revert to a flex-direction of row. As this is the default behavior we can omit the flex-direction property. We can try setting the align-items property to center. We also set a container height of 250 pixels, to make the example clearer.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
align-items: center;
}
Here is the result:
The flex-direction property is a row, pointing from left to right. The align-items property specifies how the items are arranged in the direction perpendicular to the flex-direction. In this case, the alignment direction is vertical, and we see the items are centered vertically.
We could also set the align-items property to flex-start. When our flexbox is in row mode, the start of the container is considered to be the top.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
align-items: flex-start;
}
In the resulting layout, we see the items all pushed to the top of the container:
Similarly, we can set the align-items property to flex-end. This time we expect to see the items aligned in a row, at the bottom of the container.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
align-items: flex-end;
}
In the updated layout, we see the items pushed to the bottom of the container:
There is another option where we set the align-items property to baseline. Here, our items will be arranged so that they are aligned along a baseline. Once aligned they are pushed to the start of the container, in this case, the top, until the tallest item touches the top side.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
align-items: baseline;
}
Here is the updated layout with align-items set to baseline:
This option is really useful for navigation bars where our links and items might be different heights. In this case, it usually looks best to arrange them neatly along a horizontal baseline.
The ‘flex-wrap’ property
The flex-wrap property lets us specify what happens if the flex items do not all fit in a single row or column. Let’s consider a new HTML template with more items that we can use to illustrate the problem.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS by example</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
<div class="item item4"></div>
<div class="item item5"></div>
<div class="item item6"></div>
<div class="item item7"></div>
</div>
</body>
</html>
We have a parent div element with a class of container, and seven inner div elements with a class of item. In our CSS file, we set the item size to 100 pixels square and give each element a different color.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
}
.item {
width: 100px;
height: 100px;
}
.item1 {
background-color: #EEFFFF;
}
.item2 {
background-color: #CCEEFF;
}
.item3 {
background-color: #BBDDFF;
}
.item4 {
background-color: #99CCFF;
}
.item5 {
background-color: #77BBFF;
}
.item6 {
background-color: #55AAFF;
}
.item7 {
background-color: #3399FF;
}
Here is the result viewed in a web browser:
The container div element is only 600 pixels wide, but the seven inner div elements are each 100 pixels wide. The result is that they shrink and are rendered with a width of around 85 pixels each.
We can achieve a different result by setting the flex-wrap property on the container with a value of wrap.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-wrap: wrap;
}
This time six items fit on the top row, and the final element wraps onto a new line. Note the row spacing. As there are two rows, the container space is divided by two, and the second row starts 50% from the top of the container.
The wrapped rows start at the top, and additional items are placed on rows underneath. Alternatively, we could set a flex-wrap property of wrap-reverse. In this case, the first row is placed at the bottom of the container with additional rows laid out above.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-wrap: wrap-reverse;
}
Here is the resulting layout, where the first item is light blue, and the final item is dark blue.
This time the first row was placed at the bottom, flush against the bottom of the container. The second row was placed above it, flush against the top 50% of the container.
The ‘gap’ property
We can use the gap property to specify the spacing, in pixels, between items in the flexbox. The default is zero. In this example, we set a flex-wrap property of wrap, and we set the gap property to 20 pixels.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-wrap: wrap;
gap: 20px;
}
Here is the resulting layout:
We see a 20-pixel gap between each item. This increases the space consumed by the items, so an additional item is pushed onto the second row.
What would happen if we set the gap property to 100 pixels?
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-wrap: wrap;
gap: 100px;
}
As we might expect, the gap between the items is increased to 100 pixels. We see that the gap spacing is applied both horizontally and vertically.
We can set the gap property with two values: the first value is the gap between the rows, and the second is the gap between the columns.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-wrap: wrap;
gap: 15px 60px;
}
Here is the updated layout:
We can see that an additional 15-pixel gap has been inserted between the rows. The flexbox items are arranged in rows in the remaining space. Horizontally a 60-pixel gap has been introduced between each item.
What would happen if we switched the flex-direction property to column?
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 15px 60px;
}
Now the items are arranged in columns. The gap property is still applied in the same way, with a 15-pixel gap between the rows, and a 60-pixel gap between the columns.
Here is the new layout:
The ‘flex-grow’ property
We can gain more control over our flexbox by applying properties directly to one or more of the elements it contains. These properties are applied to the flex items and not the outer container.
We can use the flex-grow property to define how much space each item should take in the flexbox. We could use it if we want one item to consume more or less space than the other items.
For this example, we will reduce the number of flexbox items:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS by example</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="item item1"></div>
<div class="item item2"></div>
<div class="item item3"></div>
<div class="item item4"></div>
<div class="item item5"></div>
</div>
</body>
</html>
Now in our CSS file, we use a simple flexbox layout. For the item1 class, we apply the flex-grow property with a value of 1. This relative value tells the flexbox how much space the given item should consume. Once the items are laid out, additional space will be distributed according to these values. The default value, when it is not set, is zero.
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
}
.item {
width: 100px;
height: 100px;
}
.item1 {
background-color: #EEFFFF;
flex-grow: 1;
}
.item2 {
background-color: #CCEEFF;
}
.item3 {
background-color: #BBDDFF;
}
.item4 {
background-color: #99CCFF;
}
.item5 {
background-color: #77BBFF;
}
Here is the result displayed in a web browser:
There are five items, and the first item, in pale blue, has grown to fill all the additional space.
What would happen if we set a flex-grow value of 2 for the second item?
.item1 {
background-color: #EEFFFF;
flex-grow: 1;
}
.item2 {
background-color: #CCEEFF;
flex-grow: 2;
}
Now we expect the additional space to be shared between the first and second items. As the second item has a higher flex-grow value, we expect it to receive a larger share of the space.
Here is the resulting layout:
Sure enough, both items have stretched, but the second item occupies more space than the first.
The ‘order’ property
By default, our flexbox container will arrange the inner elements in the order they are defined in the HTML template. However, we can specify the individual elements’ order properties to change this behavior. Consider the following CSS rules:
.container {
width: 600px;
height: 250px;
background-color: #eee;
display: flex;
}
.item {
width: 100px;
height: 100px;
}
.item1 {
background-color: #EEFFFF; // Lightest color
order: 1;
}
.item2 {
background-color: #CCEEFF;
order: 3;
}
.item3 {
background-color: #BBDDFF;
order: 5;
}
.item4 {
background-color: #99CCFF;
order: 4;
}
.item5 {
background-color: #77BBFF; // Darkest color
order: 2;
}
The element with class item1 has the lightest color, through to the element with class item5 that has the darkest color. However, as we applied the order property values, they were rendered in a different order: