Vertical Centering of Inline Elements
I originally published this in June, 2006, as a simple demonstration of the results of a lot of head scratching at CSSCreator forums. I like to think I made a contribution, but it was Bruno Fasino who made the totally non-intuitive, logical leap that made everything actually work in IE≤7. Ingo Chao brought Bruno's work to those of us with slower wits, (OK, that was me; Chris..S caught on right away) and fashioned the practical model.
In this evolution, I try to make practical examples of the model as you would use it in real web pages.
It is a simple matter to center elements horizontally. All
graphic browsers since IE6, ca. 2001 have supported
{margin: auto;}
, which centers the block element
horizontally within its container. Likewise, the
text-align
property controls horizontal alignment
of inline elements within their block containers.
It would be as trivial to center vertically if the majority browser—you know who you are, IE≤7—were to support the display property's table group of values. (For the purposes of this article, IE8 may be considered a modern browser.) This article deals with centering inline elements. Various articles in the Vertical Centering Section deal with other issues of vertical centering.
Fixed Height Containers
The original problem we were trying to find an answer to
was, how do we make a vertical menu with equal height boxes,
and vertically centered text of one, two, or three
lines?
In this section, we'll demonstrate a simple block container
with multiple centered lines of text, a container with an image
and a caption
, an example of creating more content than
will fit the container, and finally, a menu.
But first, let's take a look at the way things work.
Centering Text in a Fixed Height Container
The Modern Browser
The key for modern browsers is the table-cell value for
display. We make the parent container
{display: table;}
so we can set width,
height, margins, &c., and we have a proper container for
the inline contents. An element with
{display: table-cell;}
will fill its
container if it's a table type.
So, this:
<style type="text/css">
p {
border: 1px solid black;
display: table;
height: 200px;
width: 200px;
}
span {
display: table-cell;
vertical-align: middle;
}
</style>
And, this:
<p><span>line one
<br />
line two</span></p>
Yields this:
line one
line two
You may have noticed that IE doesn't seem to be cooperating. We'll discus that in the next section.
Legacy Browsers: IE6 & IE7
The leap that Bruno made was to create two inline elements that aligned with one another. I only confuse myself when I try to rationalize what's happening, but I'll try to explain it anyhow.
What we want to do is create an anonymous inline box the
full height of the container. One way to do this is to make the
inline contents {display: inline-block;}
. In
the following explanatory illustrations, the
<span>
is colored pink, and the
<b>
is colored yellow, to help you see their
dimensions.
The html will have a conditional comment to feed IE an extra element.
<p><span>line one
<br />
line two</span><!--[if lte ie 7]><b></b><![endif]--></p>
Fig. 1
No height is given either element. The line-box's
height is determined by the tallest element, the span.
Notice that the bold (exes added for clarity) is centered
vertically against the span.
Fig. 2
We want the line-box to be the full height of the
parent container, so this time both elements are given
{height: 100%;}
. We have full height,
but remember, an inline-block element has an interior
behavior like a block element. The text is at the top, as
to be expected.
Fig. 3
Give just one element, the span, a height, and
leave the other auto. That works as desired, except that
the bold element is centered against the span; just the
opposite of what we want.
Fig. 4
Set the bold to 100%, and the unsized span aligns
itself to the middle of the line-box. Now that IE has a
work-around, the colors and unneeded text can be
removed.
Put it all Together
Removing all the extraneous stuff, we can selectively add the IE work-around to the basic method.
<p><span>line one
<br />
line two</span> <!--[if lte ie 7]><b></b><![endif]--></p>
<style type="text/css">
p {
border: 1px solid black;
display: table;
height: 200px;
width: 200px;
}
span {
display: table-cell;
vertical-align; middle;
}
</style>
<!--[if lte ie 7]>
<style type="text/css">
span {
display: inline-block;
}
b {
display: inline-block;
height: 100%;
vertical-align: middle;
}
</style>
<![endif]-->
Practical Examples
Read the source for the specifics of each example.
Simple Text and Images
Centering multiple lines
in a block container.
An image and a caption
Handling Overflow
This example shows the dangers of depending on buggy behavior to provide the desired result. Modern browsers properly expand the container, because it's displaying as a table, and that's the way tables operate. IE≤6 expands the container because an element with hasLayout expands even when it's not supposed to. Since IE uses inline-block instead of table, it shouldn't expand. IE7 has fixed this bug. The result is that IE6's bug gives the desired rendering while IE7 doesn't.
Take care that you allow sufficient height or less content to avoid this problem.
And a caption
that just
goes on,
and on,
and on,
and on some more
A Vertical Menu with Equal Sized Boxes
Notice that the list-items have a fixed height. Table displayed elements shrink-wrap their contents. For modern browsers, overflow will cause the element to expand, which is probably alright. IE6 will also expand due to having layout. IE7 will over flow. Overflow is created in the fourth list item.
- one line menu item
- two line
menu item - three
line
menu item - too many
lines in a
menu item
causes an overflow condition
Vertical Centering in Dynamic Height Containers
That's a bit misleading. All elements displayed as one of the table group are effectively of dynamic size. Any declared height or width should be considered a minimum, as a table must enclose its content.
A Horizontal Menu with Equal sized Boxes
The horizontal menu differs from the vertical in that the
ul
is now the table container and the list items
are displayed as table cells. The advantage, in modern
browsers, is that each cell will be the same height as the
others, just as a row of cells in a table are all the same
height.
Issues with IE
We must still treat IE to a fixed height. If we don't, each box will seek its own height, which is what we don't want. If we do set a height, we face the overflow issue again.
An Example
In this demo, the same markup is used as in the vertical menu; only the style rules are changed. Box height for IE is the same as above, 4em, enough for three lines.
- link1
line 2 - link2
- link3
line2
and line 3 - too many
lines in a
menu item
causes an IE overflow condition
Summary
CSS2.1 provides an elegant solution to the problem of centering one element within another. IE, being so far behind the curve on CSS support, requires heroic measures to do what other browsers do so simply. For now, it is probably a sane approach to simply use flat tables for all but the vertical menu—no matter how poorly structured and non-semantic your markup must be.
If you're careful about the possible overflow issues in IE, Bruno's sweet little hack is easy to apply, if not to grok in fullness.