Managing Internet Explorer, JavaScript, and client and offset values returning zero
I’ve been working on building a custom modal control for someone else that will ideally be used in a variety of places throughout their site. Essentially, the control will allow a developer to create a dialog and style it how s/he would want it to appear, and then pass it to my code. My code will then process it, bundle it up with a semi-transparent background, and then overlay their dialog centered above all of the other elements on the page.
For the most part, it was going well - the control was performing the exact same way across all of the major browsers, and it was easy to plug existing code into it; however, while testing it on a variety of pages, I came across a bug that ended up plaguing me for much longer than it should have. There’s a function in the JavaScript that uses each element’s offsetWidth and offsetHeight values to center that element in the middle of browser window regardless of its size. Oddly enough, on one of the pages that I was testing, I was noticing that Internet Explorer was not properly centering the element. Upon further investigation, I noticed that the element’s offsetWidth, offsetHeight, clientWidth, and clientHeight values were all being returned as zero.
Naturally, I ended up googling around for a solution to the problem. I didn’t come up with much, but I did find this page on MSDN which ended up giving some insight - the page contained tables and they were the culprit for this behavior. Although this helped me pinpoint this problem, it didn’t help revealing a solution. Additionally, Firefox, Safari, and Opera all displayed it correctly regardless of if tables were present on the page or not. So, I resolved to spending some time understanding how tables caused this problem in hopes of coming up with a way to manage it. Ultimately, I came up with a solution and thought I’d share it here. Before diving into code, I thought I’d explain how it works.
About document.readyState
Internet Explorer implements a property on the document object called readyState. Technically, it’s present for the sake of the XmlHttp object, but it can used to determine the state of the current document (which is useful, as you’ll read shortly). There are five different ready states:
- Uninitialized
- Loading
- Loaded
- Interactive
- Complete
The important thing to take away from this is that IE will not have the offsetWidth/offsetHeight/clientWidth/clientHeight values calculated until state five, but the JavaScript function was processing the element in step four.
Capitalizing on document.readyState with IE
My fix capitalizes on document.readyState. Because Firefox, Safari, and Opera all returned ‘undefined’ for this property, it meant I didn’t have to re-write a lot of the existing functionality - I just needed to incorporate a single case for managing IE’s behaviors. Assume that this.bIsE is a flag set earlier in the code determining whether or not I’m using IE. Also assume that _InitializeComponents() contains logic responsible for getting some of the page’s elements ready. Here’s what I did:
if(this.bIsIE && document.readyState != ‘complete’) {
var self = this;
self.onLoadHandler = window.setInterval(function() {if(document.readyState == ‘complete’) {
self._InitializeComponents();
window.clearInterval(self.onLoadHandler);}
}, 100);
} else {self._InitializeComponents();
}
Basically, the way this works is that is that if it’s not IE, initialize the components and proceed; otherwise, if IE is the current browser and it’s not in the ready state, then fire the readyState check every 100ms. If the document eventually reaches the ready state, then initialize the components and stop the interval function. Overall, it’s not perfect, but it works and it accomplished what I needed.

23. July 2008 at 09:28
Wow, definitely one of the nastier bugs IE has to offer.
In my case, the JS was in an iframe from a different domain than the parent document. It seems the problem was actually with the parent document readyState, which I couldn’t query (methinks).
Finally, I simply queried the value (offsetHeight) directly. Ugly hack, but it’s holding, so far.
Thank you for taking the time to post a solution for this infuriatingly obscure bug.