Flexible height vertical centering with CSS, beyond IE7
One of the most common CSS questions is undoubtedly how to center an element vertically. There are several techniques for doing that, but many, including one that I posted more than seven years ago in Centering with CSS, rely on specifying a height for the centered content. That obviously makes the technique somewhat inflexible.
I recently needed to center something both horizontally and vertically and started thinking that there might be better ways of doing it if I could disregard IE7 and older. The technique I ended up with uses display:table
to center the whole page and seems to work well, though there is one caveat.
The HTML
The vertical centering demo page I’ve made shows how display:table
can be used to center the whole page vertically and horizontally. The only markup addition necessary is a wrapper element as a child of the body
element:
<body>
<div id="body">
Content goes here
</div>
</body>
The CSS
The CSS isn’t very complicated either. First, the width
and height
of the html
and body
elements are set to 100%
to make them fill the viewport. After that, the html
element is set to display:table
to make it behave like a table. The body
element is then told to behave like a table cell and to vertically align its content in the middle.
The horizontal centering is achieved by the normal means of giving div#body
a width through max-width
or width
(depending on whether you want a flexible width or not) and setting its horizontal margins to auto
.
And that’s all there is to it:
html,
body {
width:100%;
height:100%;
}
html {display:table;}
body {
display:table-cell;
vertical-align:middle;
}
#body {
max-width:50em;
margin:0 auto;
}
The demo page sets a few other properties like color
, background
, and padding
, but the above is what does the actual centering work.
Flexible height
As you may have noticed, the content container (div#body
) does not have a specified height. It will stretch to make room for its content, until it becomes taller than the viewport. When that happens, well, a vertical scrollbar appears, just as you would expect.
If you’re really going for that 90’s look you can give the container a height and set overflow
to auto
to have an on-page scrollbar appear when it’s needed:
#body {
max-width:50em;
height:300px;
overflow:auto;
margin:0 auto;
}
Browser support
I’ve tested this in the most recent versions of Safari, Firefox, Opera, and Chrome, and they all handle it fine. I’m not sure how far back their support for display:table
stretches, but I know that it’s been in Safari, Firefox and Opera since at least early 2004.
Microsoft added support for display:table
in Internet Explorer 8, and it works fine there and in IE9. IE7 and IE6 do not center the content vertically, but horizontally. I think that makes this technique viable for real-world use since the only thing that will happen in those browsers is that the content will start at the top of the viewport instead of being vertically centered.
CSS tables are not HTML tables
Finally, a note on using display:table
and its friends display:table-row
and display:table-cell
is in place. I’ve seen people saying that using these CSS properties to create “CSS tables” is no better than using tables in your HTML. I don’t agree with that.
Using CSS to change an element’s display properties does not change the semantics of the underlying HTML—it just changes how the element is displayed. It does not turn arbitrary HTML elements into table
, th
or td
elements.
display:table
and screen readers
Logically, display:table
should not make screen readers treat fake tables as real tables. But just to make sure I did a bit of testing and found that—unfortunately—that isn’t always the case.
As far as I can tell VoiceOver, JAWS, and NVDA have no problems at all with display:table
, i.e. they do not announce fake tables as tables. Window-Eyes announces some fake tables (I think it’s those that use display:table-row
, either implicitly or explicitly) when used with Firefox, but not when used with Internet Explorer. Orca includes all CSS tables when you use the keyboard to navigate between tables.
So that’s a bit of a drawback, and frankly I was quite surprised by this. To me it seems obvious that screen readers should look at the markup before deciding to treat something as a table. I don’t know much about the inner workings of screen readers, but a guess is that since Orca runs on top of Firefox and that the Window-Eyes problems only seem to occur when used with Firefox, the Firefox accessibility API for some reason is reporting CSS tables as real tables.
Either way this behaviour seems like a bug. There can’t be a lot of people using display:table
to emulate tables instead of using real tables for tabular data, and they should be encouraged to use HTML tables instead.
Luckily the technique I describe here only seems to affect Orca, which is likely the least used of the tested screenreaders. Plus, it will only announce the single-cell table if you actively try to find tables on the page by pressing t. So the annoyance is pretty small, but you should still be aware that this may be an issue to keep in mind and that it may happen in other screenreaders.
Test before deploying
In my testing this technique seems to work fine. I have not noticed any weird display problems, it falls back to only horizontal centering in browsers that don’t support display:table
, and most screen readers ignore the fake table as they should.
That said, there may be issues I have missed. If you’re aware of any, or have suggestions for improvement, please do get in touch.
What about flexible box layout (flexbox)?
As some readers will know, it’s possible to use the CSS 3 Flexible Box Layout Module to do this as well. It’s actually simpler and “cleaner” than using display:table
. Unfortunately flexbox is currently only supported in Gecko and WebKit browsers, which means it won’t work in Opera or IE (including IE9).
That said it may be useful in some cases anyway, and hopefully it will be supported by all major browsers before the end of the decade, so I have a separate article on flexible box layout coming up.
- Previous post: HTML5 sectioning elements, headings, and document outlines
- Next post: Source order and display order should match