additions...

...web design...

fully centered across browser-land…

I'm not sure why something should stay smack in the middle of a browser-window – both horizontally and vertically centered, but someone requested such a solution and I had time on my hands to investigate. A quick fix with 'position: fixed' or 'position: absolute' wasn't acceptable, since nothing should get lost off-screen – regardless of actual window-size.

An accessible and usable solution was needed, with the perfect vertical centering in place, and where scrollbars appeared if/when the centered element ran out of browser-window for whatever reason. It also had to work flawlessly in the majority of browsers out here, which is easier said than done.

The browser used by the majority of potential visitors, IE/win – all versions, was immediately putting up a fight. No problem centering whatever vertically in that browser, but one certainly has to ditch web standards for it to work.

Ok, I have no problems with IE/win's low standard-awareness. I'm used to throwing non-standard garbage at IE/win until it behaves acceptable. However, I do not downgrade design-solutions that works perfectly in every standard-compliant browser on earth, just to accomodate a garbage-collector like IE/win.

So here's the deal: Opera, Gecko and Safari get the best solution I can create, in the hope that they will obey standards like I'm used to from that side. Other browsers in the higher classes can follow the before mentioned's example if they can, while IE/win just has to work as if it understood standards.

vertical centering in CSS capable browsers…

HTML tables is not an option for visual layout, so a couple of divs will have to do. I don't think of two divs in one page as a case of “divitis”, so I can live with having them in there.

basic HTML:
<!DOCTYPE>
<html>
<head>
</head>
<body>
<div id="wrapper">
<div id="centered">
   some content here 
</div>
</div>
</body>
</html>

The source-code above is really all that's needed, but we have to replicate HTML tables to make it work. So, it's time to add some CSS table properties.

basic CSS:
html, body {
height: 100%; 
margin: 0; 
padding: 0;
}
body {
display: table; 
height: 100%; 
width: 100%; 
text-align: center/*for IE5 win*/;
}
#wrapper {
display: table-cell; 
vertical-align: middle;
}
#centered {
height: 20em; 
width: 30em; 
margin: 0 auto;
}

The centered element needs a 'width', but the 'height' is optional. Most units can be used, but percentages for 'height' is not reliable across browser-land.

vertical centering in IE/win…

IE/win doesn't understand CSS table properties, so we need a workaround. I have seen many workarounds on the web, but most of them mean we'll have to downgrade our entire design – source-code and all – to IE/win level, and that's simply not acceptable.

I have chosen to add an IE-expression as workaround for IE/win's deficiency. An IE-expression is a bit of Javascript tailored for use in a stylesheet. The result is non-valid CSS, but it works. Validity can always be achieved by hiding the IE-expression from the validator.

mode-independent IE-expression:
div#centered {margin-top: expression((
document.documentElement.offsetHeight/2)
-(parseInt(offsetHeight)/2) <0 ? "0" : 
(document.documentElement.offsetHeight/2)
-(parseInt(offsetHeight)/2) +'px') ;}

This expression detects the height of body and the centered element continuously, and adds the necessary amount of 'margin top' to make the centered element stay vertically centered.

how this expression works:
  1. document.documentElement.offsetHeight/2
    extracts body-height and divides it by 2. This makes the calculated 'margin-top' half the body-height to begin with
  2. -(parseInt(offsetHeight)/2))
    extracts element-height and divides it by 2. This is then subtracted from half the body-height, and we have the calculated 'margin-top'.
  3. <0 ? "0" :
    checks if the calculated 'margin-top' will become smaller than zero. If so, set 'margin-top' to zero.
  4. <0 ? "0" :
    if the calculated 'margin-top' will become equal to or larger than zero, then repeat the calculation and use this calculated 'margin-top' for vertical alignment.

Note that I have added a small correction, a 2px subtraction, in the expression used in the demo pages. This is a “cosmetic fix” for a minor offset in IE/win, and not worth bothering with.

variant of vertical centering in IE/win…

For cases where vertical centering has to be repeated several times in a document – for example in a multi-cell CSS table which can only be realized in IE/win through some serious workarounds, calculating offset based on the height of the document is of no use. Selecting element by ID is also only good for one element in a page.

The this keyword provides some freedom since we can then select the element by class and apply vertical centering almost everywhere with one IE-expression. There there are still severe limitations compared to what can be achieved in CSS capable browsers though.

IE-expression using the 'this' keyword:
.vertical-align-middle target-element {
margin-top: expression(((this.parentElement.offsetHeight/2)
-(parseInt(this.offsetHeight)/2) -2) <0 ? "0" : 
(this.parentElement.offsetHeight/2)
-(parseInt(this.offsetHeight)/2) -2 +'px') ;}

This expression detects the height of target-element's parent and target-element itself continuously, and adds the necessary amount of 'margin top' to target-element to make it stay vertically centered within its parent. It is otherwise working as described for the regular version above, and can replace it.

The class '.vertical-align-middle' can of course be attached to the target-element itself, or any of its ancestors. Typically I would attach the class to the elements I want a vertically centered element inside.

simplified example from a typical CSS table:
<div class="row">
<div class="column">
<p>not vertically centered</p>
</div>
<div class="column">
<p>not vertically centered</p>
</div>
<div class="column vam">
<p>this is vertically centered</p>
</div>
</div>
.column {
display: table-cell;
}
.vam {
vertical-align: middle;
}

.vam p {
margin-top: expression(((this.parentElement.offsetHeight/2)
-(parseInt(this.offsetHeight)/2) -2) <0 ? "0" : 
(this.parentElement.offsetHeight/2)
-(parseInt(this.offsetHeight)/2) -2 +'px') ;}

Here the class 'vam' is short for 'vertical-align-middle', and the paragraph inside that div will appear to be vertically centered in the finished CSS table workaround for IE/win.

Only one element can be vertically centered within its parent with this expression. The target-element also has to be the only element within its parent for this to work.

So, we can simulate CSS table's 'vertical-align: middle' in non-table construction by using IE-expressions. The simple expressions shown above will only get us so far though, so it would indeed be nice if Microsoft got an upcoming version up to the relevant CSS specs – one day.

finally…

I can think of quite a few situations where an identical or somewhat similar workaround for IE/win can come handy, so the time used to figure it all out and writing it down was definitely well spent. Besides, boredom is underrated as driving-force, and should be put to good use more often.

The good browsers are doing well, and IE/win is behaving acceptable when we don't push it too hard. I don't think we can ask for more right now, so I'll leave it at that and continue developing for more CSS capable browsers.

sincerely  georg; sign

Hageland 28.mar.2007
last rev: 06.oct.2007

additions...

about…
…2007