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.

Beating the IE Resize Bug

So it turns out that there are actually a number of problems with the solution I've proposed in this blog entry. It seems to work for my sample page, but when put to the test in a real world scenerio, it failed miserably.

An updated solution has been posted: Beating the IE Resize Bug (revisited).

And you can see this updated solution in action here.

There is a bug (at least I consider it a bug) in IE (versions 6 and 7) in which the clarity between window.onresize and body.onresize is muddied. This can cause quite a problem for developers and even render the client's browser unresponsive (throttling the CPU to near 100%) if you're not very careful.

I've discussed this with numerous members of the IE development team, and I was able to gain some valuable insight. The general feeling was that this behavior is by design. It may be (and I can understand the motivation to do this), but I'm still not so sure I agree with it (it just doesn't feel logical to me).

After quite a bit of back-and-forth, I finally got in touch with one developer who seemed to think that this is the wrong behavior (in strict mode). Personally, I feel that this behavior is undesirable in either strict mode or transitional, but I guess just having the issue acknowledged is a good start.

The problem remains though, because this bug affects developers today, and it won't be addressed for quite some time (if I'm not mistaken, the official IE7 release is not going to address it).

So in this blog entry, my goal is to introduce a work-around that I've come up with for dealing with this issue.

Read on to learn more.

Continue reading Beating the IE Resize Bug

Mutual Exclusion with minimal javascript

With toilet cleaner becoming so popular for building web applications (oh c'mon, toilet cleaner — it's not that hard to figure out), it's not at all uncommon to run into a scenario in which you need to make one option, among a list of options, appear to be selected without doing any sort of page refresh or linking to another page.

Often, only one of these options can appear selected at a time, so one might call these options mutually exclusive (see wikipedia for an in-depth explanation of what mutual exclusion means in the world of programming).

Now, there's a good way to accomplish this and there's a bad way; an easy way and a tedious way; an elegant way and an ugly way. And if you're anything like most poeple, you probably tend towards the latter approach.

In this blog entry, I hope to illustrate how to accomplish mutual exclusive link selection (visually) with an astonishingly small amount of Javascript code.

Continue reading Mutual Exclusion with minimal javascript

NaN (and what it means to javascript)

Not surprisingly, NaN in Javascript repesents "Not a number." You probably knew that, but here's something you may not have known.

NaN is a 'number'! Well, sort of.

Actually, it's typeof NaN that yields 'number', which, if you ask me, is little bizarre, though not completely illogical (depending on my mood).

Continue reading NaN (and what it means to javascript)

The javascript ternary operator

Pop Quiz: Do you understand the Javascript ternary operator?

You said "yes" didn't you? Alright hotshot. See if you can analyze these statements correctly:


var x = 'steve_' + 10 == 10 ? 'A' : 'B';
alert(x);

If you answered 'steve_A', you'd be wrong.

How about:


var y = 'steve_' + (10 == 10) ? 'C' : 'D';
alert(y);

You think the answer is 'steve_C'? Wrong again.

How about:


var z = 'steve_' + (10 == 10 ? 'E' : 'F');
alert(z);

'steve_E'? Ok, that one was easy.

But what about the first two examples? Why aren't they yielding the obvious answer? Read on to find out.

Continue reading The javascript ternary operator

Safely referencing objects in javascript (understanding null and undefined)

Part 1

Javascript is a finicky language. If you don't have an in-depth knowledge of the language specifications, some of the little nuances can really throw you off.

One area in particular where I've noticed a lot of confusion among javascript programmers is regarding the null and undefined types. In this article, I'm going to examine the difference between null and undefined (yes, there is a difference, subtle though it may be).

Then, I'm going to talk about what roll the null and undefined types play when trying to determine if it is safe to access a property or method of an object (or whether or not it is even safe to access the object itself).

Finally, I'm going to propose a solution for safety checking before attempting to access some object's properties or methods.

Let's get started!

Continue reading Safely referencing objects in javascript (understanding null and undefined)

CSS Computed Style

Programmers who are new to javascript are often delighted to discover that it's remarkably easy to modify the style of some existing DOM element, like so:


var myDiv = document.getElementById('myDiv');
myDiv.style.left = '10em';
myDiv.style.backgroundColor = '#369';

The above code snippet will grab a reference to the element on the page whose id is myDiv, and modify that element's .left css property to '10em' and its .backgroundColor css property to '#369'. Nothing earth-shattering here.

Conversely, javascript programmers are often dismayed that the following may or may not work:


var myDiv = document.getElementById('myDiv');
myDiv.style.top = parseInt(myDiv.style.top) + 100 + 'px';

Notice that I said may or may not work. In what cases will it work and it what cases won't it work? Glad you asked (because the answer is easy). Read on to learn more.

Continue reading CSS Computed Style

setTimeout Revisited

In my last article, I talked about the problem of passing object parameters to a setTimeout(..) function and how that problem can be solved by using closures. While that method works, I failed to mention that there is an alternative approach if you happen to have the luxury of developing only for the Netscape/Mozilla model (lucky you).

Now, before you stop reading because you think a technique that only works in Mozilla doesn't have much value, let me say that after I explain this technique, I'm going to explore a way to duplicate the technique in IE.

But first things first. Let's explore what setTimeout syntax Mozilla offers us to handle this problem.

Continue reading setTimeout Revisited