Understanding vertical-align

Have you ever had trouble getting the vertical‑align property in CSS to work? The first time I tried to use it, I assumed it would be as easy to use as text‑align, where I could tell it to align two elements vertically, and it would. But it wasn’t quite that simple. So I searched the Internet for help and I found other people who had the same problem, but I couldn’t find anyone who had a solution. From reading online support sites, it seems like a lot of people have had to resort to CSS workarounds in order to vertically align elements, or layout their page differently because they never did get vertical‑align to work. If you are one of those people, you will want to read on, because I assure you that the vertical‑align property really does work.

The vertical‑align style depends on a couple of other properties, namely line‑height and font‑size, both of which can be inherited from a parent element, or else they “cascade” from the browser or user settings by default. If an element has a font‑size style set, but no line‑height, then the line‑height will be adjusted by the browser to accommodate the font size plus leading (extra room for line spacing). The line height for each element is used to vertically align them with each other. This will be true even if the font‑size and line‑height styles are inherited from parent elements.

In this sense, the concept of inheritance is blurred a bit, because the browser will create a containing box that wraps all of the elements in the line of text. It determines the line height of the containing box by comparing the line‑height of each element in the line, and then the inline elements use the line‑height from that containing box in order to vertically align themselves. It makes perfect sense to do it that way but it does seem a little confusing at first. There is more detailed information about how the containing box is sized on this page: Line box, Line stacking and Content height .

I remember reading on a couple of forums that people were trying to vertically align elements that could not really be aligned. The vertical‑align style only applies to inline elements. It does not apply to block elements, and if you think about it, it only makes sense to align elements vertically if they are arranged in a horizontal row, as inline elements are. Block elements, which generally have an implied line feed before and after the element, can not be vertically aligned, nor can elements with position fixed or absolute.

The key to understanding vertical‑align is in understanding how it determines the containing box that a row of inline elements fit into. The W3C explains on the page Line height calculations: the ‘line‑height’ and ‘vertical‑align’ properties that, “for inline non‑replaced elements, the box used for alignment is the box whose height is the ‘line‑height’ (containing the box’s glyphs and the half‑leading on each side. For all other elements, the box used for alignment is the margin box”. The inline non‑replaced elements they are referring to are simply regular inline elements, which means that for inline elements the current line‑height, or height in the case of an inline img, determines the height of the box, but for inline replaced elements the height will be the height of the margin box. You can read more about the difference between inline non‑replaced elements and inline replaced elements on Calculating heights and margins.

Let’s look at some examples.

Consider the following HTML code:

<body>
	Parent Element
	<div style="display:inline-block; background-color:#ffc0c0; border:1px solid red; padding:0 0.5em 0;">
		Inline Div
		<span style="background-color:#a0ffa0;">Nested Span</span>
	</div>
	<span style="background-color:#c0c0ff;">Span Element</span>
	<img src="/images/bridge.jpg" style="height:150px;" />
<body>


which renders output that looks like this:


Notice how the Span Element, and the other elements, extend slightly lower than the image, with the text aligned evenly with the bottom of the image. This is because the line‑height of the Span Element includes half‑leading, which extends slightly above and below the actual character glyphs the element contains, but the default vertical alignment is “baseline” which aligns everything with the baseline of the font glyphs in the text of elements that can contain text, not with the bottom of the element itself. Since the image contains no text, its baseline is the bottom of the image itself. See Baseline Alignment for more information on how the baseline is determined.

Now let’s take a look at how changing the font‑size automatically changes the line‑height. An element’s default line‑height, as calculated by the browser, will be the font‑size plus any leading for line spacing, which is determined by the browser. If an element explicitly specifies a line‑height that is larger than the font size, then the line height will be larger than what is necessary to accommodate the font‑size. If an element explicitly specifies a line‑height that is smaller than the font‑size, then the line height will actually be shorter than the font size itself.

Inline Div font-size:10mm;
In this example, we set font‑size:10mm for the Inline Div, and leave all other elements alone. Notice how the red box around the Inline Div is larger than in the example above. That is because the line‑height changed when the font‑size changed. Also notice how the child Nested Span element inherited both font‑size and line‑height from its parent.


Inline Div font-size:10mm; line-height:30mm;
If we add a larger line‑height to the Inline Div, but not to the Nested Span, you can see how the line‑height for the div becomes much larger. It appears as though the Nested Span does not inherit the line‑height from the Inline Div, but that is only because the span element’s background‑color only covers the text and not the entire line‑height. It is also interesting to notice how the bottom border of the Inline Div descends lower than all of the other elements. This is because none of the elements have a vertical‑align style set yet, so they all default to a vertical‑align set to “baseline”. It is very important to remember that when elements are vertically aligned to the baseline, the whole element will be shifted vertically up or down so that the baseline will be aligned with the baseline of the other elements.


Inline Div font-size:10mm; line-height:30mm;
Nested Span font-size:14px;
If we were to set the font‑size for the Nested Span explicitly to a smaller size, it would no longer inherit the parent element’s font‑size style, but it remains aligned to the baseline of the containing box.


That is a brief overview of how font‑size affects line‑height and how line‑height affects vertical‑align. Now let’s look at the vertical‑align style.

I think there are probably three general problems that people have with vertical‑align. I think the main problem is understanding the different ways that elements can be vertically aligned by setting the style to baseline, middle, text‑top, etc. Another big problem is in understanding how the containing box is determined. A third problem is that it seems like there is some confusion about which element should receive the vertical‑align style.

In the last example, I pointed out that the bottom of the Inline Div descends lower than the rest in order to align all of the baselines of the elements in the line of text. The bottom of the containing box will be the bottom of the Inline Div since it is the element the extends lower in the line. The top of the containing block will be the top of the image since it is the highest element in the line. The baseline is usually the bottom of the characters, except that some characters, such as the “p” in the Span, use a baseline that is not the absolute bottom of the character, so those characters will extend below the baseline.

Inline Div font-size:10mm; line-height:30mm;
Nested Span font-size:14px; vertical-align:text-top;
If we continue with the same styles in the previous example, but we add a vertical‑align style of “text‑top” to the Nested Span, what do you suppose will happen? The Nested Span will align itself with the top of the content area of the Inline Div. However, it doesn’t immediately appear that way. It looks like it pushes the Nested Span much lower than it should. Remember when I said that span elements do inherit line‑height, but the background‑color does not cover the entire height of the element, but only the height of the content area? Well, that is why it appears to not work correctly. The Nested Span inherits a line‑height of 30mm and aligns that 30mm box with the top of the content area of the Inline Div, which is the top of the text plus the half‑leading. There is not enough room to align the Nested Span with the top of the Inline Div’s content area and still fit the 30mm high element inside the Inline Div, which is also 30mm. Thus, the Inline Div’s bottom border is extended below the actual line‑height of the Inline Div in order to accomodate the child element’s vertical alignment and line‑height. But if you didn’t know all of that, it might appear as though vertical‑align doesn’t work correctly.


Inline Div font-size:10mm; line-height:30mm;
Nested Span font-size:14px; vertical-align:text-bottom;
Setting the Nested Span’s vertical‑align to “text‑bottom” will have the same effect only it will align to the bottom of the Inline Div’s content area and push the top of the Inline Div up in order to accommodate the Nested Span.


So we have multiple things going on. There is a containing box around all of the elements, and there is another containing box inside of the Inline Div that determines how the Nested Span element is aligned in there. So there is a baseline for the elements outside of the Inline Div, and a separate baseline inside the Inline Div. Let’s change a few things and see what happens.

Inline Div font-size:10mm; line-height:30mm; vertical-align:bottom;
Nested Span font-size:14px; vertical-align:baseline;
We have set the vertical‑align for the Nested Span to “baseline”, and we have set the vertical‑align for the Inline Div to “bottom”. So, inside the Inline Div, the Nested Span is aligned with the baseline of the other text so it is perfectly lined up, even though the font sizes are different. Outside of the Inline Div, there is a good example of the difference between the “bottom” and “baseline” settings for vertical‑align. You can see the the Inline Div is aligned perfectly with the bottom of the other elements, but the image still has its default “baseline” setting for vertical‑align, so it aligns with the bottom of the text, not the bottoms of the elements. The visual difference is subtle, but noticeable.


One of the most common problems I have read in online discussions about vertical‑align is people trying to align a smaller element to the middle of a larger element. They often put the vertical‑align style in the smaller element thinking that it will cause the smaller element to rise up and position itself in the middle of the larger element. But this does not always work, depending on what kinds of elements you are working with and what styles they have, particularly font‑size and line‑height. I have found it is usually a better practice to put the vertical‑align style in the larger element. It is also important to always be aware of the top and bottom of your containing box, and also be aware of the baseline in the line of text your are working with.

In our most recent example, we have two containing boxes, so we have two different baselines. Another very common thing I’ve heard people trying to do with vertical‑align is to align some text with the middle of an image. How would we go about this in our example? First of all, if we want to align the text in all of the elements, even inside the Inline Div, we would need to establish a single baseline again, because right now we are dealing with two separate ones. Then we would have to figure out how to get all of those text elements aligned with the middle of the image. For illustrative purposes, we will do them separately beginning with the vertical alignment.

Inline Div font-size:10mm; line-height:30mm; vertical-align:bottom;
Nested Span font-size:14px; vertical-align:baseline;
Image vertical-align:middle;
The image will take the vertical‑align style, not the span elements or inline‑block divs. Even though it is more intuitive to think of it as aligning text with the middle an image, CSS thinks of it as aligning the middle of an image with text.


As expected, it is not aligned the way we have hoped. The text inside the Inline Div is aligned, and the text outside the Inline Div is aligned to the middle of the image. So we need to bring the two baselines together by setting the vertical‑align for the Inline Div back to baseline, or leave it empty because baseline is the default. This will set all vertical alignment in our line of text back to one single baseline for all elements.

Inline Div font-size:10mm; line-height:30mm;
Nested Span font-size:14px; vertical-align:baseline;
Image vertical-align:middle;
And there we have it. All of the elements are aligned with each other by their baseline, and some of them have different font sizes and line heights, some with borders, etc. but all of them aligned with the middle of the image.


There are lots of other settings for vertical‑align that I have not discussed here. I have not touched on setting it to a percentage or a length. There is a little bit more information on CSS/Properties/vertical‑align.

It is somewhat confusing and might take some experimenting before you really grasp all of it. So I created a vertical‑align tool that you can use to experiment with every possible vertical‑align setting yourself.

Note: The images for the examples in this post were created from screen shots of the webpage running on Firefox 22.0.