Vertical Centering With CSS using vertical-align: middle

Note from 2018: Nowadays, if your browser demographic allows it, you might want to use flexbox.

If I need to vertically center elements with CSS I almost always end up using display: inline-block together with vertical-align: middle. vertical-align may not always behave the way you expect it to—I’ve dedicated a complete article to it—but here it’s the solution to go for.

A Quick Example

Yay, I'm centered in the blue min-height area!
Click to change content height

The minimal markup and CSS:

<div class="container">
  <div class="center-area"><!--
    --><div class="centered">Yay, I'm centered ...!</div>
  </div>
  <div class="content">
    <!-- Some content defining the
         height of the container -->
  </div>
</div>

<style type="text/css">
  .container {
    min-height: 8em;
    position: relative; /* so center-area can
                           be positioned absolute */
  }
  .center-area {
    /* let it fill the whole container */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
  }
  .center-area:before {
    content: '';
    display: inline-block;
    vertical-align: middle;
    height: 100%;
  }
  .centered {
    display: inline-block;
    vertical-align: middle;
  }
</style>

Why this way? It is the solution that works in almost all situations:

  • You don’t need to know the dimensions of the elements to be centered, at all.
  • You don’t need to know the the size of the outer area your elements are centered in upfront. You need to know and set it at some point (more on that below), but your CSS doesn’t need to change for individual heights.
  • It works for block and inline elements alike, since you explicitly set the display property.
  • It is semantically clean by not adding any helper elements to your mark-up besides one pseudo-element.
  • It is supported across browers (IE8+).
  • It is able to vertically center more than one element next to each other.

Especially, that the height of the centered element(s) can be flexible sets this method apart from all other methods relying on absolute positioning with negative margins or margin: auto. This makes the vertical-align method the most maintainable. Need to replace an image with one of a different size? No problem, just set the path to the new file. You can leave the CSS alone. Or are you centering a block of text? Rewrite the text and it is still perfectly aligned.

The technique is also explained on CSS-Tricks.

Vertical Centering in an Area of Unknown Height

There is one drawback, if you want to call it one: It does not work, if the height of the outer element is determined by the height of its content. This means, it does not work, if the height property of the outer element evaluates to auto eventually. This particularly happens in the following scenarios (Have a look at the CSS specs about height for more details.):

  • You do not set height at all. It defaults to auto.
  • You do set height, but you set it to auto. Even if you set a min-height to an absolute length, say 200px, height still evaluates to auto. It needs to be prepared, if your content makes the element taller than its min-height. The height then becomes defined by the content, again.
  • You do set height to a percentage, but the parent’s height evaluates to auto. You end up with height been set to auto for your element, because it contributes to the height of its parent. Otherwise it could happen, that the element increases the height of its parent. Which in turn would increase the height of the element, because of its percentage height. This increases the height of the parent, again. Which leads to… To infinity and beyond!

Why do we need a definite height on the outer element? Because the pseudo-element in our solution has a height set to 100%. Look at the last bullet point above to see, what happens, if the outer element’s height evaluates to auto. The pseudo-element gets a height of auto, too. Its content is an empty string. So its height will be one line-height, not the full height of its parent.

So, is this bad, after all? To vertically center something, you need to know the top and bottom edge of the area to center in. If you cannot fix these bounds by any means, neither by setting an explicit height nor by positioning the top and bottom of an absolute positioned element, you cannot expect to center something in there.

A Small Fix For The White-Space Problem

But there is still something, that I dislike about this approach. You have to take care of the white-space between inline-elements in your mark-up. The markup looks like:

<div class="center-area">
  <div class="centered"></div>
</div>

If we included the pseudo-element, it would look like:

<div class="center-area">::before
  <div class="centered"></div>
</div>

So, there is white-space between the ::before and the <div.centered>: a line-break and some spaces. It all collapses to one space according to the rules html is processed by. This single space is nudging our centered element a bit to the right and might break the layout. Even worse, the space’s size differs for different fonts. For example, it is .625em for Courier and .25em for Helvetica. To keep that out of the equation, the white-space must be removed. There are two options:

  • Put both opening tags into one line:

    <div class="center-area"><div class="centered">
    </div></div>
  • Keep the indentation and add a comment to filter out the line-break and spaces.

    <div class="center-area"><!--
     --><div class="centered"></div>
    </div>

Changing the indentation of the mark-up or adding comments at the right places can be frustrating to maintain. But once you know it, it is quickly fixed and making it the lesser evil in my opinion.

Further Reading

If you despair of vertical-align from time to time, I recommend having a look at my in-depth article All You Need To Know About Vertical-Align.