In pure CSS, a working answer will one day be to just use "display:table-cell"
. Unfortunately that doesn't work across current A-grade browsers, so for all that you might as well use a table if you just want to achieve the same result anyway. At least you'll be sure it works far enough into the past.
Honestly, just use a table if it's easier. It won't hurt.
If the semantics and accessibility of the table element really matter to you, there is a working draft for making your table non-semantic:
http://www.w3.org/TR/wai-aria/#presentation
I think this requires a special DTD beyond XHTML 1.1, which would just stir up the whole text/html
vs application/xml
debate, so let's not go there.
So, on to your unresolved CSS problem...
To vertically align two elements on their center: it can be done a few different ways, with some obtuse CSS hackery.
If you can fit within the following constraints, then there is a relatively simple way:
- The height of the two elements is fixed.
- The height of the container is fixed.
- The elements will be narrow enough not to overlap (or can be set to a fixed width).
Then you can use absolute positioning with negative margins:
.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }
But this is pointless in most situations... If you already know the height of the elements, then you can just use floats and add enough margin to position them as needed.
Here is another method which uses the text baseline to vertically align the two columns as inline blocks. The drawback here is that you need to set fixed widths for the columns to fill out the width from the left edge. Because we need to keep the elements locked to a text baseline, we can't just use float:right for the second column. (Instead, we have to make the first column wide enough to push it over.)
<html>
<head>
<title>Layout</title>
<style type="text/css">
.group-header, .group-content { width: 500px; margin: 0 auto; }
.group-header { border: 1px solid red; background: yellow; }
.valign { display: inline-block; vertical-align: middle; }
.group-content { border: 1px solid black; background: #DDD; }
.group-title { padding: 8px; width: 384px; }
.group-buttons { padding: 8px; width: 84px; text-align: right; }
</style>
<!--[if lt IE 8]>
<style type="text/css">
.valign { display: inline; margin-top: -2px; padding-top: 1px; }
</style>
<![endif]-->
</head>
<body>
<div class="group-header">
<div class="valign">
<div class="group-title">This is my title.</div>
</div><!-- avoid whitespace between these! --><div class="valign">
<div class="group-buttons"><input type="button" value="Collapse"></div>
</div>
</div>
<div class="group-content">
<p>And it works perfectly, but mind the hacks.</p>
</div>
</body>
</html>
The HTML: We add .valign wrappers around each column. (Give them a more "semantic" name if it makes you happier.) These need to be kept without whitespace in between or else text spaces will push them apart. (I know it sucks, but that's what you get for being "pure" with the markup and separating it from the presentation layer... Ha!)
The CSS: We use vertical-align:middle
to line up the blocks to the text baseline of the group-header element. The different heights of each block will stay vertically centered and push out the height of their container. The widths of the elements need to be calculated to fit the width. Here, they are 400 and 100, minus their horizontal padding.
The IE fixes: Internet Explorer only displays inline-block for natively-inline elements (e.g. span, not div). But, if we give the div hasLayout and then display it inline, it will behave just like inline-block. The margin adjustment is to fix a 1px gap at the top (try adding background colors to the .group-title to see).