Learning Modern HTML and CSS — Part 14

Jeff P
15 min readNov 4, 2023

--

Flexbox!!

Ok so it’s finally time to review Flexbox, which is a far more modern way of controlling layouts on pages.

Flexbox is applied to a container element, and impacts the child elements which are referred to as “Flex items”. You set Flexbox on the container element using display: flex

The default “main axis” runs horiztonally, left to right, and the “cross-axis” runs vertically, top to bottom.

Using Flexbox

We’ll start with some boilerplate HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- link to the CSS file -->
<link rel="stylesheet" href="styles.css">

<title>Mastering Flexbox!</title>

</head>
<body>
<div class="container">
<div class="el el--1">HTML</div>
<div class="el el--2">and</div>
<div class="el el--3">CSS</div>
<div class="el el--4">is</div>
<div class="el el--5">cool</div>
<div class="el el--6">when</div>
<div class="el el--7">using</div>
<div class="el el--8">flexbox</div>
</div>
</body>

</html>
.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
}

.el--1 {
background-color: blueviolet;
}

.el--2 {
background-color: orangered;
}

.el--3 {
background-color: green;
height: 150px;
}

.el--4 {
background-color: goldenrod;
}

.el--5 {
background-color: palevioletred;
}

.el--6 {
background-color: steelblue;
}

.el--7 {
background-color: yellow;
}

.el--8 {
background-color: crimson;
}

And we’ll take a look at how this looks in the browser to start with….

the green CSS section is taller because we’ve added a height of 150px, but apart from that, these are standard “block” elements, that flow on the page, and are staked vertically as expected.

Our elements are inside a parent “container” element, and this element has a margin of 40px on all sides. Also note that we’ve specified a background colour of grey for the container element, but we cannot currently see it because we don’t have any padding for the container element, and therefor the child elements are currently occupying the full area of the container element.

Ok… let’s switch this to a flexbox model!

To do this we simply, state the display: flex on the parent continer…

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
}

Now let’s look at our page….

Now all of the child elements are put side-by-side, and in terms of width, occupy the exact width needed to contain the text inside them. They are all of equal height, and this is set based on the child element with the biggest height, which in this case is the green CSS element set to 150px.

We can also now see some background, because the container covers the full width of the page, and because the child elements don’t require all that space, we then see the remaining background colour.

Vertical alignment (align-items)

Currently the height of all of the items automatically set to the same height based on the height of the tallest item, but if you want items to align vertically, and only take up the space necessary, then you can use the align-items: center; option

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: center;
}

As you can see, all elements now are centered vertically and only take up the vertical space necessary.

You can also use align-items: flex-start and align-items: flex-end to set them at the top or bottom:

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: flex-start;
}
.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: flex-end;
}

We can also stretch items to make them stretch to the same height as the tallest item in the parent element using stretch:

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: stretch;
}

Horizontal alignment (justify-content)

We can also align items horizontally with justify-content: center

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: stretch;
justify-content: center;
}

If you want to distribute all the available space in the parent container (i.e. the grey space) between the elements evenly, you can use justify-content: space-between;

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: stretch;
justify-content: space-between;
}

you can also apply a gap of a specified amount of pixels to the flex items, which would be similar to applying margin-right to items. For example:

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: stretch;
gap: 15px;
}

Switching directions!

Flexbox by default operates horizontally like a row, with flex items running left to right, and the gap being applied horizontally. However, you can actually change flexbox from running horizontally to running vertically, by simply setting flex-direction to column:

flex-direction: column:

By doing this, the components will then stack in a column (like normal “block” elements, and when you apply the gap property, it will be applied downwards, instead of sideways.

so as a quick recap:

- Horizontal: justify-content

- Vertical: align-items

The way I personally remember which way round they are…..

Justify is Jorizontal ! :-)

Aligning individual elements

We can of course control the positioning of individual elements in the parent container, and to do this we assign a flex property to the individual element. To demonstrate, I’ll first set the items back to this setup….

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: center;
}

and the display is back to this layout…

now we’ll make the first item to to the top and the second item go to the bottom in terms of vertical alignment using align-self.

.container {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display: flex;
align-items: center;
}

.el--1 {
background-color: blueviolet;
align-self: flex-start;
}

.el--2 {
background-color: orangered;
align-self: flex-end;
}

You can also change the order in which the elements are displayed, using the order property. By default, all elements in the flex container are given an order value of 0, which menas that if you wanted to take the yellow box and place it at the front, you’d have to specify a value less than 0, so we’ll set it to -1

.el--7 {
background-color: yellow;
order: -1;
}

Similarly, if you want to move something to the end, then it needs to be the highest order number, which at this moment is still 0, so we can set a value to 1 and it will go to the end. Let’s move the orange box to the end.

.el--2 {
background-color: orangered;
align-self: flex-end;
order: 1;
}

Growing and shrinking flex items

We can grow and shrink items using flex-grow and flex-shrink

Lets say that we want the red element to grow horizontally so that there is no longer any available horizontal space…. we can set flex-grow to 1 on that element (by default, flex-grow is set to 0 on all flex items)

.el--8 {
background-color: crimson;
flex-grow: 1;
}

which creates this….

using flex-grow ratios

The interesting thing about flex grow is that you can also use for ratios, and what I mean by this, is that if you set one flex item to a flex-grow value of 1, and another flex item to a value of 4, then the item with the value of 4 will take out four times as much available space as the item that was set to a value of 1.

Rather than grow the item the whole occupying space, you might want to just make it grow to a specific width, such as 600px wide. In this case you don’t use flex-grow, but instead use flex-basis

Flex-basis

Rather than grow the item the whole occupying space, you might want to just make it grow to a specific width, such as 600px wide. In this case you don’t use flex-grow, but instead use flex-basis

.el--8 {
background-color: crimson;
flex-basis: 600px;
}

now if we applied this width to the blue, red and orange elements, (totaling 1800px) then this would actually be wider than the remaining available space….let’s see what happens if we do…

.el--1 {
background-color: blueviolet;
align-self: flex-start;
}

.el--2 {
background-color: orangered;
align-self: flex-end;
order: 1;
flex-basis: 600px;
}

.el--3 {
background-color: green;
height: 150px;
}

.el--4 {
background-color: goldenrod;
}

.el--5 {
background-color: palevioletred;
}

.el--6 {
background-color: steelblue;
flex-basis: 600px;
}

.el--7 {
background-color: yellow;
order: -1;
}

.el--8 {
background-color: crimson;
flex-basis: 600px;
}

We get this….

The elements have grown, but they are definitely not 600 pixels wide… we can check this with the browser inspector…

The items are actually 351px wide…. because they’ve been constrained by the parent flex container. The reason for this is that flex items have “flex-shrink” turned on by default, and the default value is 1. You can actually see this in the bottom right corner of the inspector in the image above.

By default flex-basis is set to “auto”. When flex-basis is not explicitly set, it takes the content size of the flex item as its initial size. This means that if one item has more content than another, it will start with a larger size, and the distribution of space according to flex-grow may not work as expected.

By setting flex-basis to 0, you’re telling the flex container that you want to distribute available space evenly among flex items based on their flex-grow values. This ensures that each item starts with an equal initial size, and the remaining space is distributed accordingly.

If you don’t want the items to be constrained by flex-shrink, then you would need to switch off flex-shrink by setting flex-shrink to 0.

.el--1 {
background-color: blueviolet;
align-self: flex-start;
}

.el--2 {
background-color: orangered;
align-self: flex-end;
order: 1;
flex-basis: 600px;
flex-shrink: 0;
}

.el--3 {
background-color: green;
height: 150px;
}

.el--4 {
background-color: goldenrod;
}

.el--5 {
background-color: palevioletred;
}

.el--6 {
background-color: steelblue;
flex-basis: 600px;
flex-shrink: 0;
}

.el--7 {
background-color: yellow;
order: -1;
}

.el--8 {
background-color: crimson;
flex-basis: 600px;
flex-shrink: 0;
}

which now gives us this….

You can also write all of these properties in a single line shorthand, which is far quicker and easier:

// equivalent of setting flex-grow, flex-shrink, and flex-basis values
flex: 0 1 50px

Using Flexbox for real-word challenges

Ok so how can we use flexbox to alight items as we would for a real web-page?

Let’s create a header with a h1 and a navbar….

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- link to the CSS file -->
<link rel="stylesheet" href="styles.css">

<title>Mastering Flexbox!</title>

</head>
<body>

<header>
<h1>Mastering Flexbox!</h1>

<nav>
<ul>
<a href="#">Home</a>
<a href="#">Products</a>
<a href="#">About Us</a>
<a href="#">Contact</a>
</ul>
</nav>
</header>

</body>

</html>

And some default CSS:

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

header {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
padding: 20px;

}

header h1 {
/* STARTER */
font-size: 40px;
padding: 20px;
}

header nav {
/* STARTER */
padding: 20px;
}

without using flexbox yet, it looks like this

Ok so to move the nave bar to the top right corner, we can first of all define the <header> element as the flex container…

header {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
padding: 20px;
display: flex;
}

which means the flex container element now places the elements along the main axis…

So the next thing is to apply all of the available space in the container horizontally (or should I say “Jorizontally”!) between the two flex items in the container…. and the simplest way of doing this, is to simply set

justify-content: space-between

header {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
padding: 20px;
display: flex;
justify-content: space-between;
}

which now ensures the available space remaining in the container element is applied between the flex items, and because there are only two flex items in the container, all the space will go between them.

Now what about if we wanted to create a main article section below our header, occupying 75% of the width of the page, and an aside section on the right, occupying 25% of the page.

Let’s start with some HTML….

<body>

<header>
<h1>Mastering Flexbox!</h1>

<nav>
<ul>
<a href="#">Home</a>
<a href="#">Products</a>
<a href="#">About Us</a>
<a href="#">Contact</a>
</ul>
</nav>
</header>

<main>
<article>
<h2>Article</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
</article>

<aside>
<h2>Aside</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
</aside>
</main>

</body>

</html>

now some basic CSS styling….

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

header {
/* STARTER */
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
padding: 20px;
display: flex;
justify-content: space-between;
}

header h1 {
/* STARTER */
font-size: 40px;
padding: 20px;
}

header nav {
/* STARTER */
padding: 20px;
}

main {
padding: 20px;
}

article {
/* STARTER */
padding: 20px;
background-color: #ddd;
}

aside {
/* STARTER */
padding: 20px;
border: 1px solid lightblue;
background-color: lightgreen;
}

At this stage, this is what we have….

So how can we make the article section be on the left, and occupy 75% width, and the aside section on the right, and occupy 25% of the width?

First let’s apply flex to the container element, which is <main>

main {
padding: 20px;
display: flex;
}

Now we’ll use flex-grow with ratios of 3:1 on the flex items, but it’s important to remember that by default, flex-basis is set to “auto”, therefore by setting flex-basis to 0, you’re telling the flex container that you want to distribute available space evenly among flex items based on their flex-grow values.

So let’s also set flex basis to 0. The shorthand version of this would be as follows:

main {
padding: 20px;
display: flex;
justify-content: space-between;
}

article {
/* STARTER */
padding: 20px;
background-color: #ddd;
flex: 3 1 0;
}

aside {
/* STARTER */
padding: 20px;
border: 1px solid lightblue;
background-color: lightgreen;
flex: 1 1 0;
}

which creates this….

It would then just be a case of fine-tuning the styling, and maybe increase the padding a bit more, as well as perhaps adding some margin-right to the article section…

main {
padding: 20px;
display: flex;
justify-content: space-between;
}

article {
/* STARTER */
padding: 70px;
background-color: #ddd;
flex: 3 1 0;
margin-right: 50px;
}

aside {
/* STARTER */
padding: 35px;
border: 1px solid lightblue;
background-color: lightgreen;
flex: 1 1 0;
}

which gives us this…

This makes life much easier, especially as it ensures that both columns are of equal length…. but what if you didn’t want that….what if the article section was quite long, but the aside just a had a few links in it, and you didn’t need it to stretch the entire length of the article section?

Let’s change the HTML text to it’s easier to visualise…

  <main>
<article>
<h2>Article</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora reiciendis nisi culpa, facilis illum optio nostrum, animi voluptates nulla ratione doloremque esse dolorum quis neque ea aperiam ad! Accusantium, iure.</p>
</article>

<aside>
<h2>Aside</h2>
<p>A very short paragraph.</p>
<p>A very short paragraph.</p>
<p>A very short paragraph.</p>
</aside>
</main>

</body>

</html>

this is what it looks like…

But rather than the aside stretching all the way down like this with what seems like a lot of wasted space, we can now just make it as long as it needs to be with align-self: flex-start

main {
padding: 20px;
display: flex;
justify-content: space-between;
}

article {
/* STARTER */
padding: 70px;
background-color: #ddd;
flex: 3 1 0;
margin-right: 50px;
}

aside {
/* STARTER */
padding: 35px;
border: 1px solid lightblue;
background-color: lightgreen;
flex: 1 1 0;
align-self: flex-start;
}

which gives us this…

Finally, what if we wanted a footer section with the same nav items in it, only this time they were centered and equally spaced with a gap of 100px between them?

Let’s first create the HTML…

  <footer>
<nav>
<ul>
<a href="#">Home</a>
<a href="#">Products</a>
<a href="#">About Us</a>
<a href="#">Contact</a>
</ul>
</nav>
</footer>

and some CSS:

footer {
/* STARTER */
padding: 20px;
background-color: lightcoral;
font-size: 20px;
}

which looks like this:

and now lets apply flex to the parent container, which in this instance would be the <ul> and center the flex items and apply a gap of 100px

ul {
display: flex;
gap: 100px;
justify-content: center;
}

which give us this….

--

--

Jeff P
Jeff P

Written by Jeff P

I tend to write about anything I find interesting. There’s not much more to it than that really :-)

No responses yet