Centering a div within a div

Today I'm going to be centering a div within a div.

This is one of those simple things that's surprisingly hard if you don't do frontend development every day. Anyone who has ever wanted to build a simple product UI has come across this problem and been annoyed by it.

I haven't done enough front end development for it to really matter, but recently as I built this blog site, it was irritating me that I kept fumbling through these basic layout questions. Even with GitHub copilot wired up, I was spending a lot of time trying to get things to look the way that I wanted.

So today I'm going to be working on fixing that. I'll be using flexbox as the modern way to accomplish this because that's what copilot recommended.

Starting with the defaults

To start with let's look at how things appear using the default display property of a CSS item. I'll create a container with three items.

<div class="demo-container">
    <div class="demo-item">Item 1</div>
    <div class="demo-item">Item 2</div>
    <div class="demo-item">Item 3</div>
</div>

Let's also color each of the items and the container itself so that it's easy to see.

.demo-container {
    display: block;
    background: #FCF5D9;
    padding: 0.125em;
    border-radius: 0.25em;
}

.demo-item {
    background: #D5DFEC;
    border: 2px solid #4D74A8;
    padding: 0.25em;
    margin: 0.25em;
    border-radius: 0.25em;
}

Here's the result.

Item 1
Item 2
Item 3

There's a few things that are worth calling out at this point.

  1. The width of each item fills the full width of the parent.
  2. The height of each item matches the height of the content in that item.
  3. The items are stacked vertically.

Next, let's explore what happens as we start making changes to the CSS. To keep things less verbose, I'll keep the exact same HTML elements and classes, and only show the CSS changes.

Adding display: flex

Let's add flexbox now.

.demo-container {
    display: flex;
}

And here is the result.

Item 1
Item 2
Item 3

Let's compare this to the display: block that we had previously.

  1. The width of each item now fills the full width of the content, not the parent.
  2. The height of each item matches the height of the content in that item - that's still the same.
  3. The items are stacked horizontally, not vertically.
  4. The items are justified to the left of the container.

If we're going to accomplish our goal of centering a div within a div, we're going to first need to center thos items within their parent container. Let's see how to do this.

Justifying items

To change how the items are justified within their container, we use the justify-content attribute.

.demo-container {
    display: flex;
    justify-content: center;
}
Item 1
Item 2
Item 3

And of course we can justify the content to the right as well.

.demo-container {
    display: flex;
    justify-content: right;
}
Item 1
Item 2
Item 3

Or we can justify the content to have equal spacing between the items.

.demo-container {
    display: flex;
    justify-content: space-between;
}
Item 1
Item 2
Item 3

Aligning items

In the examples above, you'll notice that all items have the same height. What happens if one item has a larger height than all the others?

First I'll add some new classes to our example so we can control the individual items.

<div class="demo-container">
    <div class="demo-item demo-item-1">Item 1</div>
    <div class="demo-item demo-item-2">Item 2</div>
    <div class="demo-item demo-item-3">Item 3</div>
</div>

Then let's change the height of a single item.

.demo-container {
    display: flex;
    justify-content: center;
}

.demo-item-1 {
    height: 1.75em;
}
Item 1
Item 2
Item 3

This is not a mistake. Notice that even though we only specified the height of one item, the height of all the items changed. By default, flexbox will give all items the same height, matching the height of the tallest item.

Let's try to give all items a specific height, and then change the height of a single item.

.demo-container {
    display: flex;
    justify-content: center;
}

.demo-item {
    height: 1em;
}

.demo-item-1 {
    height: 1.75em;
}
Item 1
Item 2
Item 3

Now that the items have different heights, notice how the items are aligned on the top of the container.

We can change the alignment with the align-items property. For example, let's align the items along the center of the parent container.

.demo-container {
    display: flex;
    justify-content: center;
    align-items: center;
}

.demo-item {
    height: 1em;
}

.demo-item-1 {
    height: 1.75em;
}
Item 1
Item 2
Item 3

This looks almost like what we want. The items are aligned along the center of the container, but the text within the items is not. Yuck.

One way to fix this is to also make the items themselves flexbox containers. Then, use align-items to control the position of the content within the items.

.demo-container {
    display: flex;
    justify-content: center;
    align-items: center;
}

.demo-item {
    height: 1em;
    display: flex;
    align-items: center; 
}

.demo-item-1 {
    height: 1.75em;
}
Item 1
Item 2
Item 3

Now we can center a div

So the two properties we need to use are align-items: center and justify-content: center. The item being centered also needs to use display: flex as well, with align-items: center for its content.

I'll also add some height to the container and reduce the number of items.

.demo-container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 6em;
}

.demo-item {
    display: flex;
    align-items: center; 
}

.demo-item-1 {
    height: 1.75em;
}
Item 1

Wow. We've centered a div within a div.