The IE Resize Bug (revisited)

To see the resize demo in action, browse to the revised Resize Demo Page.

In my last blog entry, I talked about an IE reisze issue (IE failing to properly distinguish between a resize that happens to the <body> element and one that happens to the window (or viewport)).

In that blog entry, I proposed a solution for getting around this issue by ditching IE's built-in resize event entirely and writing some custom code to manage it instead. Specifically, the technique centered around an absolutely positioned DIV whose CSS instructed it to fill the viewport. We then used a bit of javascript (executed at regular intervals) to monitor the size of the DIV.

While this technique worked in my sample page, it failed when put to the test in a real world scenerio. The major problem I ran into was that if the <body> element were manually made smaller or larger any time during the resize logic (something you might want to do to manage scrollbars and page layout) some strange behavior would ensue.

Given that my technique turned out to be less robust that I would have liked, I went back to the drawing board to try to come up with a better design.

What I ended up with was a similar technique, but one that didn't require any CSS (which is a plus) and which centered around a getViewportSize(..) function courtesy of James Edwards (aka Brothercake) and Cameron Adams (highly recommend picking up their book: "The Javascript Anthology").

So enough of my babbling. Let's take a look at the revised sample:


<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.0 TransitionalEN" "http:www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

  <head>
    <script type = "text/javascript">
   function resize()
   {
    var currentSize = getViewportSize();
    if (currentSize[0] != g_prevSize[0] || currentSize[1] != g_prevSize[1])
    {
     g_prevSize = currentSize;
     debug.value = 'the window was resized: ' +
                   document.documentElement.clientWidth + ', ' +
                   document.documentElement.clientHeight;
    }
   }

   function init()
   {
    window.debug = document.getElementById('debug');
    window.g_prevSize = getViewportSize();
    setInterval(resize, 100);
   }

   function grow()
   {
    var p = document.createElement('p');
    p.appendChild(document.createTextNode('This is a paragraph'));
    document.body.appendChild(p);
   }


   function getViewportSize()
   {
    var size = [0, 0];
    if (typeof window.innerWidth != 'undefined')
    {
     size = [ window.innerWidth, window.innerHeight ];
    }
    else if (typeof document.documentElement != 'undefined' &amp;&amp;
             typeof document.documentElement.clientWidth != 'undefined' &amp;&amp;
             document.documentElement.clientWidth != 0)
    {
     size = [ document.documentElement.clientWidth, document.documentElement.clientHeight ];
    }
    else
    {
     size = [ document.getElementsByTagName('body')[0].clientWidth,
              document.getElementsByTagName('body')[0].clientHeight ];
    }

    return size;
   }
  </script>

  <style type = "text/css">
   body { border: 2px solid red; }
  </style>
 </head>

 <div id = "resizer"></div>
 <body onload = "init()">

  <input id = "debug" type = "text" size = "80" /><br />


  <button id = "btn" onclick = "grow()">Grow</button>
 </body>

</html>

The conept here is pretty simple. Like the technique used in the previous blog entry, once again we create a global reference to the previous viewport size (g_prevSize) when the page initially loads and then call setInterval(resize, 100); to monitor that viewport size at 100ms intervals.

In the resize(..) function itself, we determine the current viewport size (currentSize) and compare that against g_prevSize. If the width of currentSize (represented by index 0 in the array returned by the getViewportSize(..) function) is [i]different[/i] from the width of g_prevSize OR if the height of currentSize (represented by index 1) is different from the height of g_prevSize, then we know that the viewport size has changed, and hence, the window must have been resized.

Once we've determined that a resize has occurred, we simply update the value of g_prevSize and then go ahead with our resize logic.

If your resize logic is complicated and consists of many lines of code (or perhaps even if it doesn't) you may want to consider calling a separate function for it. In a real-world scenerio for example, after I determine that a resize needs to take place, I call a function, doResize(..).

I find this to be a bit cleaner than stuffing the resize detection and the resize logic all in one function.

So I think this is pretty straight-forward and not tremendously different from the technique used in my previous blog entry (though hopefully a bit more robust).

Comments welcome.

4 thoughts on “The IE Resize Bug (revisited)”

Leave a Reply

Your email address will not be published. Required fields are marked *