All You Need To Know About Vertical-Align

Often I need to vertically align elements side by side.

CSS offers some possibilities. Sometimes I solve it with float, sometimes with position: absolute, sometimes even dirty by manually adding margins or paddings.

I don’t really like these solutions. Floats only align at their tops and need to be cleared manually. Absolute positioning takes the elements out of the flow so they do no longer affect their surroundings. And working with fixed margins and paddings immediately breaks things on the tiniest change.

But there is another player here: vertical-align. I think it deserves more credit. Ok, technically, using vertical-align for layout is a hack, since it wasn’t invented for this reason. It’s there to align text and elements next to text. Nonetheless, you can also use vertical-align in different contexts to align elements very flexible and fine-grained. The sizes of elements need not to be known. Elements stay in the flow so other elements can react to changed dimensions of those. This makes it a valuable option.

Peculiarities Of Vertical-Align

But, vertical-align can be a real scumbag sometimes. Working with it can be a little frustrating. There seem to be some mysterious rules at work. For example, it might happen, that the element you changed vertical-align for doesn’t change its alignment at all, but other elements in the line do! I’m still getting dragged into the dark corners of vertical-align from time to time, tearing my hair.

Unfortunately, most resources on the matter are somewhat shallow. Especially, if we want to use vertical-align for layout. They concentrate on the misconception of trying to vertical align everything inside an element. They give basic introductions into the property and explain how elements are aligned in very simple situations. They do not explain the tricky parts.

So, I set myself the target to clarify the behavior of vertical-align once and for all. I ended up working through the W3C’s CSS specifications and playing with some examples. The result is this article.

So, let’s tackle the rules of the game.

Requirements To Use Vertical-Align

vertical-align is used to align inline-level elements. These are elements, whose display property evaluates to

Inline elements are basicly text.

Inline-block elements are what their name suggests: block elements living inline. They can have a width and height (possibly defined by its own content) as well as padding, a border and margin.

Inline-level elements are laid out next to each other in lines. Once there are more elements that fit into the current line, a new line is created beneath it. All these lines have a so-called line box, which encloses all the content of its line. Differently sized content means line boxes of different height. In the following illustration the top and bottom of line boxes are indicated by red lines.

A tall in a line of text.
A short in a line of text.
This can happen.

The line boxes trace out the field we are playing on. Inside these line boxes the property vertical-align is responsible for aligning the individual elements. So, in respect to what are elements aligned?

About Baselines and Outer Edges

The most important reference point to align vertically is the baseline of the involved elements. In some cases the top and bottom edge of the element’s enclosing box becomes important, too. Let’s have a look where the baseline and outer edges live for each involved type of element:

Inline Element

aAÄ qQ

aAÄ qQ

aAÄ qQ

Here you see three lines of text next to each other. The top and bottom edge of the line height is indicated by red lines, the height of the font by green lines and the baseline by a blue line. On the left, the text has a line height set to the same height as the font-size. The green and red line collapsed to one line on each side. In the middle, the line height is twice as large as the font-size. On the right, the line height is half as large as the font-size.

The inline element’s outer edges align themselves with the top and bottom edge of the line height. It does not matter, if the line height is smaller than the height of the font. So, the outer edges are the red lines in the figure above.

The inline element’s baseline is the line, the characters are sitting on. This is the blue line in the figure. Roughly speaking, the baseline is somewhere below the middle of the font’s height. Have look at the W3C Specs for a detailed definition.

Inline-Block Element

c

c

From left to right you see: an inline-block element with in-flow content (a “c”), an inline-block element with in-flow content and overflow: hidden and an inline-block element with no in-flow content (but the content area has a height). The boundaries of the margin is indicated by red lines, the border is yellow, the padding green and the content area blue. The baseline of each inline-block element is shown as a blue line.

The Inline-block element’s outer edges are the top and bottom edge of its margin-box. These are the red lines in the figure.

The Inline-block element’s baseline depends on whether the element has in-flow content:

Line Box

x This can happen.

You’ve already seen this setting above. This time I drew in the top and bottom of the line box’s text box (green, more on this below) and the baseline (blue), too. I also highlighted the area of the text elements by giving them a grey background.

The line box has a top edge aligned to the top edge of the top-most element of this line and a bottom edge aligned to the bottom edge of the bottom-most element of the line. This is the box indicated by the red lines in the figure above.

The line box’s baseline is variable:

CSS 2.1 does not define the position of the line box's baseline.

This is probably the most confusing part, when working with vertical-align. It means, the baseline is placed where ever it needs to be to fulfil all other conditions like vertical-align and minimizing the line box’s height. It is a free parameter in the equation.

Since the line box’s baseline is invisible, it may not immediately be obvious where it is. But, you can make it visible very easily. Just add a character at the beginning of the line in questions, like I added an “x” in the figure. If this character is not aligned in any way, it will sit on the baseline by default.

Around its baseline the line box has what we might call its text box. The text box simply is an inline element inside the line box without any alignment. Its top and bottom edges are defined by the line height. This box is indicated by the green lines in the figure above. Since this text box is tied to the baseline, it moves when the baseline moves. (Side note: this text box is called strut in the W3C Specs)

Phew, this was the hard part. Now, we know everything to put things into perspective. Let’s quickly sum up the most important facts:

The Values Of Vertical-Align

By using vertical-align the reference points mentioned in the last sentence in the list above are set into a certain relationship.

Aligning the Element’s Baseline Relative To the Line Box’s Baseline

x baseline sub super -50% +10px

Aligning the Element’s Outer Edges Relative To the Line Box’s Baseline

x middle

Aligning the Element’s Outer Edges Relative To the Line Box’s Text Box

x text-top text-bottom

One could also list these two cases under aligning relative to the line box’s baseline, since the position of the text box is determined by the baseline.

Aligning the Element’s Outer Edges Relative To the Line Box’s Outer Edges

x top bottom

The formal definition is found in, of course, the W3C Specs.

Why Vertical-Align Behaves The Way It Behaves

We can now take a closer look at vertical alignment in certain situations. Especially, we will deal with situations where things might have gone wrong.

Centering an Icon

One question bugging me was the following: I have an icon I want to center next to a line of text. Just giving the icon a vertical-align: middle didn’t seem to center it in a satisfying way. Have a look at this example:

Centered?

Centered!

<!-- left mark-up -->
<span class="icon middle"></span>
Centered?

<!-- right mark-up -->
<span class="icon middle"></span>
<span class="middle">Centered!</span>

<style type="text/css">
  .icon   { display: inline-block;
            /* size, color, etc. */ }

  .middle { vertical-align: middle; }
</style>

Here is the example again, but I drew in some auxiliary lines you already know from above:

x Centered?

x Centered!

This sheds some light on our matter. Because the text on the left isn’t aligned at all, it sits on the baseline. The thing is, by aligning the box with vertical-align: middle we are aligning it to the middle of the lower case letters without ascenders (half of the x-height). So, characters with ascenders stand out at the top.

On the right, we take the whole area of the font and align its midpoint vertically, too. The text’s baseline shifts slightly below the line box’s baseline to achieve this. The Result is a nicely centered text next to an icon.

Movement Of the Line Box’s Baseline

This is a common pitfall when working with vertical-align: The position of the line box’s baseline is affected by all elements in that line. Let’s assume, an element is aligned in such a way, that the baseline of the line box has to move. Since most vertical alignment (except top and bottom) is done relative to this baseline, this results in an adjusted position of all other elements in that line, too.

Some Examples:

There Might Be a Little Gap Below Inline-Level Elements

Have a look at this setting. It’s common if you try to vertical-align li elements of a list.

<ul>
  <li class="box"></li>
  <li class="box"></li>
  <li class="box"></li>
</ul>

<style type="text/css">
  .box { display: inline-block;
         /* size, color, etc. */ }
</style>

As you can see, the list items sit on the baseline. Below the baseline is some space to shelter the descenders of a text. This is causing the gap. The Solution? Just move the baseline out of the way, for example by aligning the list items with vertical-align: middle:

<ul>
  <li class="box middle"></li>
  <li class="box middle"></li>
  <li class="box middle"></li>
</ul>

<style type="text/css">
  .box    { display: inline-block;
            /* size, color, etc. */ }
            
  .middle { vertical-align: middle; }
</style>

A Gap Between Inline-Level Elements Is Breaking the Layout

This is mainly a problem of inline-level elements themselves. But since they are a requirement of vertical-align, it is good to know about this.

You can see this gap in the former example between the list items. The gap comes from the white-space between inline-elements present in your mark-up. All white-space between inline-elements is collapsed into one space. This space gets in the way, if we want to place two inline elements next to each other and giving them width: 50%, for example. There is not enough space for two 50%-elements and a space. So the line breaks into two lines destroying the layout (left). To remove the gap, we need to remove the white-space, for example with html comments (right).

50% wide

50% wide... and in next line

<!-- left mark-up -->
<div class="half">50% wide</div>
<div class="half">50% wide... and in next line</div>

<!-- right mark-up -->
   <div class="half">50% wide</div><!--
--><div class="half">50% wide</div>

<style type="text/css">
  .half { display: inline-block;
          width: 50%; }
</style>

Vertical-Align Demystified

Yea, that’s it. It is not very complicated once you know the rules. If vertical-align does not behave, just ask these questions:

This will corner the solution to the problem.