Centering Things in CSS

Hello! I am back. It's been a very busy and hectic month. Last week I went out to the Far West Texas desert to stay at the Indian Lodge, which is a very cool motel found in the Davis Mountains State Park, built by the CCC in the 1930's. There is no internet service and very unreliable cell service out there, so I got to spend a few days away from screens, hiking around the desert, and enjoying the stars in one of the darkest night sky areas on the planet. Here's a picture from that trip:

View from the top of Skyline Drive at sunset over the West Texas Desert. There are mountains off in the distance and golden prairies underneath a blue sky.

I got back to Austin just in time to learn that another big winter storm was coming. It's been almost exactly a year since the February 2021 winter storm knocked out the entire state of Texas for almost an entire week. With that memory fresh in mind, all my efforts went into preparing - making sure we had enough food, clean water, and charged up batteries/power sources in case we lost power, water, or heat. This storm wound up just being a couple days of sleet, icy roads, and a little bit of snow. Nothing nearly as bad as last year, but it was good to be prepared. We're out of the storm now, but Austin is currently under a water boil notice for a couple of days.

Beyond all of that, you can probably tell I'm slowing down my publishing pace on this blog. Once a week got to be pretty aggressive toward the end of last year, and I burned through a lot of my shorter blog posts ideas. Now I'm mostly left with longer posts that require a lot more research and time, such as this one.

I also have a big announcement to make: next week I will be starting a new job as Senior Web Engineer at Sprout Social! I'm both very excited and very nervous. I'm also sad to be leaving Austin PBS, where I have grown so much over the last five years, but it's time to begin a new chapter. I'm sure I'll be writing more about this transition (and maybe a retrospective on Austin PBS) in the future.

This is all a long way of saying that in order to protect my bandwidth, focus on my new job, and make sure the longer posts I publish meet my standard of quality, I will not be publishing here as frequently as I have been.

In the meantime, here's a breakdown of a topic that has been written about to death and I think is a required post for just about every web development blog out there: Centering Things in CSS. Admittedly I don't write a lot about HTML and CSS, so please excuse me if this post is a little clumsier than my usual posts, but I thought I would give it a wild first shot. Aim for the stars, even if you miss you land among the fences. Or however that saying goes. You miss 100% of the divs that you don't center-align.

This isn't an exhaustive list of centering techniques, and really it focuses on centering a single item within a div. There are far more strategies that achieve this, and even more if you're trying to center multiple items within their containers. If I missed something big, please reach out to me at joey@joeyreyes.dev, and I will be glad to add more examples and give you credit.

One last quick note: I really struggled to figure out the best way to display HTML and CSS code snippets alongside examples of the results of those code snippets. I spent a long time trying different things out (even moving from Markdown to .mdx!!), and ultimately landed on embedding Codepen iFrames for each example. I'm not the happiest about this solution, but it does give me a chance to play around more in Codepen. I made a collection of all of the examples that follow, and that collection can be found here.

Horizontal Centering

Horizontally Centering Inline and Inline-* Elements

When applied to a parent element, the text-align CSS property will adjust any inline (or inline-*) child elements within that parent element. The center value will horizontally align these items to the center:

<div class="container">
  Inline element (text) to be horizontally centered
</div>
.container {
  /* Horizontally center inline child elements */
  text-align: center;
}

This is also a handy way to apply even horizontal spacing on either side of a group of links:

<div class="container">
  <a href="https://joeyreyes.dev">Home</a>
  <a href="https://joeyreyes.dev/blog">Blog</a>
  <a href="https://joeyreyes.dev/about">About</a>
</div>
.container {
  /* Horizontally center inline child elements */
  text-align: center;
}

Horizontally Centering Block Elements

If we are aiming to horizontally center a block element, like a div, then we can use margin: 0 auto;. This tells the block element to have its left and right margins take up 100% of the space available to them. Note that the block element should have a fixed width, otherwise it would default to the full width of the container and not need to be horizontally centered.

<div class="container">
  <div class="block-element">
    Block element (div) to be horizontally centered
  </div>
</div>
.block-element {
  /* Set block element to fixed width */
  width: 400px;

  /* Horizontally center block element */
  margin: 0 auto;
}

Horizontally Centering Flex Items

Flexbox is one of the newer positioning techniques in the frontend toolkit, and a number of properties make aligning things very easy. To horizontally center a flex item within a flex container, you can use justify-content: center;:

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be horizontally centered within flex container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Horizontally centers flex items */
  justify-content: center;
}

Note that the justify-content property defines content distribution along the main axis of the flex container. By default the main axis is horizontal. If you have set the flex-direction to column, then the flex direction is vertical. To achieve horizontal alignment in this situation, you should turn to the align-items property, which defines content distribution along the cross axis of the flex container:

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be horizontally centered within flex column container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Define a column direction */
  flex-direction: column;

  /* Horizontally centers flex items */
  align-items: center;
}

Horizontally Centering Grid Items

You can use a similar property, justify-items to control content distribution along the inline axis (aka the row axis) of the grid container:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be horizontally centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;

  /* Horizontally center grid items */
  justify-items: center;
}

You can also control the horizontal distribution of a single grid item by setting that item's justify-self property to center:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be horizontally centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}

.grid-item {
  /* Horizontally center grid item */
  justify-self: center;
}

Depending on the type of element that the grid item is, you can also use the text-align: center; or margin: 0 auto; techniques detailed above. Admittedly, creating a grid container to center a single item is a bit silly.

Vertical Centering

Vertically Centering Inline and Inline-* Elements

The first and most basic way to vertically center an inline (or inline-*) element is to adjust the vertical padding on its parent element. This works especially well if that parent element doesn't have a defined height. The padding you specify will help define how much space it takes up:

<div class="container">
  Inline element (text) to be vertically centered
</div>
.container {
  /* Give the container equal top and bottom padding */
  padding-top: 88px;
  padding-bottom: 88px;
}

Note: I chose a 88px at random, just wanting to give it a good amount of vertical spacing to demonstrate the technique. You could also go with the shorthand padding: 88px 0;.

A second way to vertically center inline elements is to set the line-height and height properties to the same value:

<div class="container">
  Inline element (text) to be vertically centered
</div>
.container {
  /* Set height and line-height to the same value */
  height: 200px;
  line-height: 200px;
}

This technique feels super hacky, but it'll work. The hackiness will be especially apparent if you click and highlight the text, as you'll see the unnaturally tall white space above and below the highlighted text selection.

These two techniques work best for shorter text that doesn't wrap. If your text starts to grow longer, you might start running into issues. Another technique for vertically aligning inline elements is to set the parent element to display: table;, and set the child element to display: table-cell;. This will allow you to use vertical-align: middle; on the child element, snapping it to the vertical center of its parent. Note that this only works if the parent has a set height. This technique will accommodate longer text.

<div class="container">
  <p>Some longer text to be vertically centered. Did you know that the puffin is not actually the national bird of Iceland? That title goes to the Gyrfalcon, which is the largest falcon in the world.</p>
</div>
.container {
  /* Set parent element to display: table */
  display: table;
}

.container p {
  /* Set child element to display: table-cell */
  display: table-cell;

  /* Set vertical-align to middle */
  vertical-align: middle;
}

This is really just making a non-table element behave and display like a table. The same can be achieved with the following:

<table>
  <tr>
    <td>Some longer text to be vertically centered. Did you know that the puffin is not actually the national bird of Iceland? That title goes to the Gyrfalcon, which is the largest falcon in the world.</td>
  </tr>
</table>

Vertically Centering Block Elements

If you know the height of the block element that you are trying to vertically center, then you can do the following:

  1. Set position: relative; on the the parent/container
  2. Set position: absolute; on the child/block element that you are centering
  3. Set top: 50%; on the child/block element
  4. Set margin-top to be the negative of half of the height. If this element has a height of 100px, then margin-top should be -50px. If this element has a height of 60px, then margin-top should be -30px.
<div class="container">
  <div class="block-element">
    Block element (div) to be vertically centered
  </div>
</div>
.container {
  /* Set parent position to relative */
  position: relative;
}

.block-element {
  /* Set child position to absolute */
  position: absolute;

  /* Set child to fixed height */
  height: 60px;

  /* Set top position to 50% */
  top: 50%;

  /* Set margin-top to negative half of height */
  margin-top: -30px;
}

If however you don't know the element's height, you can use transform: translateY(-50%); instead of the negative margin-top trick:

<div class="container">
  <div class="block-element">
    Block element (div) to be vertically centered
  </div>
</div>
.container {
  /* Set parent position to relative */
  position: relative;
}

.block-element {
  /* Set child position to absolute */
  position: absolute;

  /* Set top position to 50% */
  top: 50%;

  /* Transform-translate Y axis -50% */
  transform: translateY(-50%);
}

Vertically Centering Flex Items

Vertical centering is, of course, much easier to accomplish with Flexbox. If your main axis is horizontal (the default for Flexbox), you can simply use align-items: center; on the flex container:

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be vertically centered within flex container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Vertically centers flex items */
  align-items: center;
}

Otherwise, if flex-direction is set to column, then horizontal centering takes place along the main axis, so you simply need to use justify-content: center;:

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be vertically centered within flex column container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Define a column direction */
  flex-direction: column;

  /* Vertically centers flex items */
  justify-content: center;
}

Vertically Centering Grid Items

The align-items property also works within CSS Grid to align along the block axis (i.e., the column axis) of the grid container:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be vertically centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;

  /* Vertically center grid items */
  align-items: center;
}

Or, if you're trying to center an individual element within the grid, you can use that grid item's align-self property:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be vertically centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}

.grid-item {
  /* Vertically center grid item */
  align-self: center;
}

Horizontal and Vertical Centering

This post is getting to be very long, but the good news is that we're able to combine the techniques we've covered so far to achieve both horizontal and vertical centering.

Horizontally and Vertically Centering Inline and Inline-* Elements

Here's text-align: center; combined with equal vertical padding to center the text along both axes:

<div class="container">
  Inline element (text) to be horizontally and vertically centered
</div>
.container {
  /* Horizontally center inline child elements */
  text-align: center;

  /* Give the container equal top and bottom padding */
  padding-top: 88px;
  padding-bottom: 88px;
}

Or achieve the same effect by combining text-align: center; with that hacky height/line-height technique:

<div class="container">
  Inline element (text) to be horizontally and vertically centered
</div>
.container {
  /* Horizontally center inline child elements */
  text-align: center;

  /* Set height and line-height to the same value */
  height: 200px;
  line-height: 200px;
}

Or combine text-align: center; with the display: table; and display: table-cell; technique:

<div class="container">
  <p>Some longer text to be vertically centered. Did you know that the puffin is not actually the national bird of Iceland? That title goes to the Gyrfalcon, which is the largest falcon in the world.</p>
</div>
.container {
  /* Horizontally center inline child elements */
  text-align: center;

  /* Set parent element to display: table */
  display: table;
}

.container p {
  /* Set child element to display: table-cell */
  display: table-cell;

  /* Set vertical-align to middle */
  vertical-align: middle;
}

Or just text-align: center; within an actual table element:

<table>
  <tr>
    <td>Some longer text to be vertically centered. Did you know that the puffin is not actually the national bird of Iceland? That title goes to the Gyrfalcon, which is the largest falcon in the world.</td>
  </tr>
</table>
table {
  /* Horizontally center inline child elements */
  text-align: center;
}

Horizontally and Vertically Centering Block Elements

Centering block elements on both axes relies on the parent/container element having position: relative; and the child element having position: absolute;. Because of this, auto margin property values don't work very well. Instead we can lean on top and left positioning, and nudging the element over and up based on its explicit height and width:

<div class="container">
  <div class="block-element">
    Centered div
  </div>
</div>
.container {
  /* Set parent position to relative */
  position: relative;
}

.block-element {
  /* Set child position to absolute */
  position: absolute;

  /* Set child to fixed height */
  height: 60px;

  /* Set child to fixed width */
  width: 200px;

  /* Set top position to 50% */
  top: 50%;

  /* Set left position to 50% */
  left: 50%;

  /* Set margin-top to negative half of height */
  margin-top: -30px;

  /* Set margin-left to negative half of width */
  margin-left: -100px;
}

Otherwise, if its height and width aren't known, we can use transform: translate(-50%, -50%);. This CSS function serves as shorthand for translateX(-50%) and translateY(-50%):

<div class="container">
  <div class="block-element">
    Block element (div) to be horizontally and vertically centered
  </div>
</div>
.container {
  /* Set parent position to relative */
  position: relative;
}

.block-element {
  /* Set child position to absolute */
  position: absolute;

  /* Set top position to 50% */
  top: 50%;

  /* Set left position to 50% */
  left: 50%;

  /* Transform-translate both axes -50% */
  transform: translate(-50%, -50%);
}

Horizontally and Vertically Centering Flex Items

As you may be able to guess, Flex elements are simple. Just use the justify-content: center; and align-items: center; property values.

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be horizontally and vertically centered within flex container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Horizontally centers flex items */
  justify-content: center;

  /* Vertically centers flex items */
  align-items: center;
}

Since we're centering along both axes, these property values will also work if the flex-direction is set to column (the controls are just swapped):

<div class="flex-container">
  <div class="flex-item">
    Flex item (div) to be horizontally and vertically centered within flex column container
  </div>
</div>
.flex-container {
  /* Create a flex container */
  display: flex;

  /* Define a column direction */
  flex-direction: column;

  /* Horizontally centers flex items */
  align-items: center;

  /* Vertically centers flex items */
  justify-content: center;
}

Horizontally and Vertically Centering Grid Items

Finally, we can use the justify-items and align-items properties within a Grid:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be horizontally and vertically centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;

  /* Horizontally center grid items */
  justify-items: center;

  /* Vertically center grid items */
  align-items: center;
}

And to center the specific grid item, use justify-self and align-self:

<div class="grid-container">
  <div class="grid-item">
    Grid item (div) to be horizontally and vertically centered within grid container
  </div>
</div>
.grid-container {
  /* Create a 1x1 grid container */
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}

.grid-item {
  /* Horizontally center grid item */
  justify-self: center;

  /* Vertically center grid items */
  align-self: center;
}

Centering Stuff Cheat Sheet/Summary

  • Horizontally Centering:
    • Inline and Inline-* Elements: text-align: center; on the item's parent element
    • Block Elements: margin: 0 auto; on the item (as long as the item has a fixed width, otherwise defaults to 100% of the parent)
    • Flex Items:
      • If default flex direction: justify-content: center;
      • If column flex direction: align-items: center;
    • Grid Items:
      • If aligning at the grid container level: justify-items: center;
      • If aligning a grid item: justify-self: center;
  • Vertically Centering:
    • Inline and Inline-* Elements:
      • For shorter items/text that don't wrap:
        • Adjust the vertical padding on its parent element; or
        • Set the line-height and height the same value
      • For longer items/text that does wrap:
        1. Set the parent element to display: table;
        2. Set the child element to display: table-cell;
    • Block Elements:
      • If you know the element's height:
        1. Set position: relative; on the the parent/container
        2. Set position: absolute; on the child/block element that you are centering
        3. Set top: 50%; on the child/block element
        4. Set margin-top to be the negative of half of the height. If this element has a height of 100px, then margin-top should be -50px. If this element has a height of 80px, then margin-top should be -40px.
      • If you don't know the element's height:
        1. Set position: relative; on the the parent/container
        2. Set position: absolute; on the child/block element that you are centering
        3. Set top: 50%; on the child/block element
        4. Set transform: translateY(-50%); on the child/block element
    • Flex Items:
      • If default flex direction: align-items: center;
      • If column flex direction: justify-content: center;
    • Grid Items:
      • If aligning at the grid container level: align-items: center;
      • If aligning a grid item: align-self: center;
  • Horizontally and Vertically Centering:
    • Inline and Inline-* Elements: Just combine text-align: center; with the vertical alignment techniques:
      • For shorter items/text that don't wrap:
        1. text-align: center;
        2. Adjust the vertical padding on its parent element
        3. Set the line-height and height the same value
      • For longer items/text that does wrap:
        1. text-align: center;
        2. Set the parent element to display: table;
        3. Set the child element to display: table-cell;
    • Block Elements:
      • If you know the element's height:
        1. Set position: relative; on the the parent/container
        2. Set position: absolute; on the child/block element that you are centering
        3. Set top: 50%; on the child/block element
        4. Set left: 50%; on the child/block element
        5. Set margin-top to be the negative of half of the height. If this element has a height of 100px, then margin-top should be -50px. If this element has a height of 60px, then margin-top should be -30px.
        6. Set margin-left to be the negative of half of the width. If this element has a width of 100px, then margin-left should be -50px. If this element has a width of 200px, then margin-left should be -100px.
      • If you don't know the element's height:
        1. Set position: relative; on the the parent/container
        2. Set position: absolute; on the child/block element that you are centering
        3. Set top: 50%; on the child/block element
        4. Set left: 50%; on the child/block element
        5. Set transform: translate(-50%, -50%); on the child/block element
    • Flex Items:
      • Set the flex container to justify-content: center; and align-items: center;. This works in either flex direction
    • Grid Items:
      • If aligning at the grid container level:
        1. justify-items: center;
        2. align-items: center;
      • If aligning a grid item:
        1. justify-self: center;
        2. align-self: center;