What is the least horrible way to center an element with CSS?

Problem

I have html that looks like this:

<!DOCTYPE html> 
<head>
    <meta charset="utf-8">

    <!--[if lte IE 8]>
    <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
</head> 

<body>

<header>
  <h1>Some title thing, who knows</h1>
  <nav>
    <ul>
      <li><a href="one/">One</a></li>
      <li><a href="two/">Two</a></li>
      <li><a href="three/">Three</a></li>
    </ul>
  </nav>
</header>

</body>
</html>

If I give header an auto margin and a width, it's horizontally centered. What's the least horrible way to ensure that it's vertically centered, as well?

I am aware of the following articles which provide some discussion of the topic:

Problem courtesy of: troutwine

Solution

Since this question was tagged CSS3, here's a "least horrible" solution using CSS3's "flexbox". Unfortunately only recent versions of Safari, Chrome and Firefox support it.

html, body {
  margin:0;
  padding:0;
  height:100%;
  background:#eee;
}
header {
  width:30em;
  background:#fff;
}
body {  
  display:box;
  box-pack:center;
  box-align:center;
  box-orient:horizontal;
}

A more complete demo can be found here.

Solution courtesy of: Marcel

Discussion

Usually when I need vertical centering I use a pair of inline-block elements. You have one element that is the full height of the container, and a second element that is only the height of the content to be centered. Both are display:inline-block;vertical-align:middle.

I like to use b tags for this, because they have no semantic significance and are tiny:

<style>
    .mycontainer {text-align:center;}
    b.vcenter {display:inline-block;height:100%;width:1px;vertical-align:middle;}
    b.vcenter+b {display:inline-block;vertical-align:middle;}
</style>

<div class="mycontainer">
    <b class="vcenter"></b><b>This is my centered content<br>It makes me happy!</b>
</div>

Mind you, this specific code example wont work in IE7 because of the lack of inline-block and sibling selectors (+), but the same technique can be done using more complex code that IE7 will handle.

Discussion courtesy of: ChiperSoft

If you do NOT know the height of the header the only way I often use, requires extra html if done properly, tough you could do without.

You make the header vertical-align: middle by making it a table-cell

html{
    height: 100%;
}      
body {
    display: table;
    height: 100%;
    margin: 0 auto;
    padding: 0;
}
header {
    display: table-cell;
    vertical-align: middle;
}

note that I set 100% height on the html node, which really isnt proper css as far as I know, it should be on the body and header should be in a encapsulating div wich has display: table http://jsfiddle.net/bgYPR/2/

Discussion courtesy of: Benjamin Udink ten Cate

I don't know if there's a best way, but there are a number of different ways (depending on your situation), and many are thoroughly discussed in this article.

Discussion courtesy of: imm

I would generally not verticially center, but specify a small top margin like 20px. We don't always know enough about the end user's equipment to make an assumption about what is convenient or usable for the platform they are viewing the site on.

Discussion courtesy of: toomanyairmiles

Unfortunately, there's still nothing elegant for vertical alignment, only hacks.

Discussion courtesy of: rid

This recipe can be found in it's original form on Stack Over Flow.