Like the fixed-position element solution I mentioned at the end of part 2, my solution also involves monitoring a <div> element. The difference is, my solution monitors the size of an absolutely-positioned <div> whose CSS specifies that it fill the viewport (unlike the fixed-position solution which monitors the position of the element).
The obvious advantage of my solution is that it will work in IE6 and IE7 (as well as Firefox).
To begin, we'll need to add a new <div> to our markup so that we have something to monitor. We'll also need to write the CSS to ensure that this <div> fills the viewport.
I'll base this example off of the previous one, but I'll add a –> in front of new lines of code so that they're easy to spot.
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>IE Resize Bug</title>
<script type = "text/javascript">
–> function resize()
–> {
–> var currentSize = { h: g_resizer.offsetHeight, w: g_resizer.offsetWidth };
–> if (currentSize.h != g_prevSize.h || currentSize.w != g_prevSize.w)
–> {
–> g_prevSize = currentSize;
–> doResize();
–> }
–> }
–> function doResize()
–> {
–> var tmp = document.getElementById('tmp');
–> tmp.innerHTML = 'Window size: ' +
–> document.documentElement.clientWidth + ', ' +
–> document.documentElement.clientHeight;
–> }
function init()
{
–> window.g_resize = document.getElementById('resizer');
–> window.g_prevSize = { h: g_resizer.offsetHeight, w: g_resizer.offsetWidth };
–> setInterval(resize, 100);
}
function grow()
{
var p = document.createElement('p');
p.appendChild(document.createTextNode('I am a paragraph!'));
document.body.appendChild(p);
}
</script>
<style type = "text/css">
body
{
margin: 0;
padding: 0;
width: auto;
height: auto;
border: 3px solid red;
}
–> #resizer
–> {
–> position: fixed;
–> top: 0;
–> left: 0;
–> margin: 0;
–> padding: 0;
–> height: 100%;
–> width: 100%;
–> visibility: hidden;
–> z-index: -1;
–> }
–> * html #resizer { position: absolute; }
</style>
</head>
<body onload = "init();">
–> <div id = "resizer"></div>
–> <div id = "tmp"></div>
<button id = "btnGrow" onclick = "grow();">Grow</button>
</body>
</html>
If you're wondering about the * html #resize { position: absolute; } code in the #resizer CSS, this is a well-know CSS hack to make a rule apply only to IE6. You'll notice that for IE6, we use an absolutely-positioned element, and for IE7 and Firefox, we position the element fixed. Fixed seems to work best in IE7 and Firefox, so I've opted to use absolute only for IE6 (which doesn't support fixed positioning).
This solution shouldn't be too hard to follow. In our init() function, we create two global variables: g_resizer (a constant reference to the <div> we're monitoring) and g_prevSize (the last known size of that <div> ).
We then call setInterval(resize, 100) to execute the resize() function every 100ms (you can choose any interval that you feel is appropriate).
In the resize() function itself, we calculate the current size of the #resizer <div> and assign that value to currentSize variable. We then compare that value to the variable g_prevSize and if their sizes are different, we can conclude that the viewport (and consequently the window) has been resized.
If the sizes are different (i.e. the browser size has changed), then presumably we'll want to take some action. That is where the doResize() functions comes in. Of course, we could have combined this all into one function, but I felt that it was a little cleaner to separate out what happens when the browser is resized from the logic that actually determines if the brower was resized.
In this example, I'm simply writing the window size to the .innerHTML of the #tmp <div> as an illustration that a browser resize was in fact detected. The #tmp <div> is of course, not necessary in a real-world scenerio.
I chose not to use an alert() to illustrate the browser resize because an alert() statement in the doResize() function can actually get in the way of the browser resize detection logic that executes at 100ms intervals.
If you try out our new sample code in IE, you'll see that IE will update the contents of the #tmp <div> only when the window was truly resized and not when the body element was resized by clicking on the grow button.
A live demo is available here.
I won't say this is a perfect solution. For example, you won't get the fluid continual firing of the resize event like you would with IE's built-in resize event. Although I, personally, prefer this as I think that continual resize event firing in IE is an annoying and unnecessary waste, I can understand how some folks might desire it.
Still, I think what we've put together here is a very viable (and relatively simple) solution to solve this IE resize bug.
So once again, the moral of the story is: when IE won't do what we want, we just find a way to beat it into submission.
Comments welcome.
Pages: 1 2
3 Responses
Works great horizontally, but if I want to fit a div vertically in the browser window with no scrolling, this doesn't quite work. I resorted to adding another condition in the doResize function, comparing the document clientHeight to scrollHeight and resize my div if the absolute > 20. 20 because apparently there is some natural difference between the two even if there is no scrolling. It makes it jumpy (not great), but it works.
Kai:
Double check to be sure you're using the updated technique, which can be found here: The IE Resize Bug (Revisited). That blog post utilizes a better technique which I discovered after I posted this blog entry.
To the best of my knowledge, the newer technique works in all cases.
Dear Sir,
Thanks to your efforts I finally understand the cause of this problem.
However, this piece of Javascript will work fine too in most cases:
var wheight = 0;
var temp_height = 0;
var delay = 100;
function init(){
if(self.innerHeight)temp_height = self.innerHeight; //all except Explorer
else if(document.documentElement && document.documentElement.clientHeight)temp_height = document.documentElement.clientHeight; // Explorer 6 Strict Mode
else if(document.body)temp_height = document.body.clientHeight;// other Explorers
else temp_height = 430;
if(temp_height!=height)dosomething();
wheight = temp_height;
setTimeout('init()',delay);
}
window.onload = init;
Best regards, WN