Share us

Main Site Navigation

offsetWidth/offsetHeight useless in IE9, FF4*

OK, I must admit "useless" is a too harsh word but the thing is our beloved offsetWidth/offsetHeight JavaScript DOM properties are now not accurate any more in Internet Explorer 9 and Firefox 4. Firstly introduced in IE4 in 1997, these DOM properties are the simplest and quickest way of getting the computed pixel dimensions (the border-box) of any page element and they used to work perfectly in all browsers released since then. Well, not any more in IE9 and FF4. Read on to learn why and what you can do to workaround the issue...

* A special note for Firefox on Windows/LinuxFirefox 4 on Windows and Linux has this issue only when hardware accelerated rendering is enabled in the Options/Preferences (and, of course, supported on the machine). I always get the issue on Mac.

IE9 and FF4 introduced subpixel font rendering and now calculate and report width/height of page elements using float values even when a web page is viewed at 100% zoom level. This is something no other browser has ever done before. So, right now in IE9 and FF4 you can get computed width/height values for block elements reported like "100.34px", "11.65px", etc. I once heard from a colleague that a client asked him to move a page element by half a pixel because apparently one pixel seemed to much to him. Well, I've got good news for that guy, this is now possible!

But seriously, let's get back to the issue. As you already may be guessing, the problem with offsetWidth/offsetHeight in IE9 & FF4 is that these properties are integer values so in these browsers the values are computed by rounding the float values for width/height and adding the padding & border. And the rounding often leads to 1px inaccuracy depending on the calculations done in your scripts and on the exact fonts and font sizes used on the page. You may say 1px is nothing but there are cases when 1px could cause quite notable issues like, for example, text wrapping happening when it shouldn't, etc..

Demoing the Problem

Basically now you can easily stumble upon issues in IE9 and FF4 like on this demo page. In this example, offsetHeight is used to get the computed border-box height of the first DIV and the second DIV has negative top margin applied which is equal to the value returned. The end result should be perfectly overlapping DIVs, so that you could only see the second one. But in IE9 or FF4, you can see either the top or the bottom border of the first DIV sneaking beneath the second DIV for some of the iterations:

The Workaround

From the demo above we clearly see we can no longer use offsetWidth/offsetHeight if we want perfect results in these browsers. The workaround is to use the getComputedStyle() method instead which reports the width/height of block elements with float numbers. So basically, the workaround is to get the computed width/height and then add the computed top/bottom padding & border of the element to get the final value. The problem with getComputedStyle() on theory is that for width/height of inline elements it always reports 'auto'. But the good news is these browsers only seem to round the computed float values for block elements and so for inline elements we can still safely use offsetWidth/offsetHeight! Well, if you are still following me, here is a fully cross-browser workaround compatible with all other and older browsers:

This is terrible!
getComputedStyle is around 5 times slower than accessing offsetWidth in IE9 (even using .width insted of .getPropertyValue('width') ), it'd be a real pain when you have to resize a lot of elements correctly.

It seems that FF5 has fixed this behaviour. Sadly, the issue with IE9 still remains.

Good question As far as I can see, in FF4 getBoundingClientRect() returns even preciser float values for width/height than getComputedStyle() (e.g. 1994.36669921875) while in IE9 the returned values are integers and are equal to offsetWidth/Height. So both browsers are inconsistent here.