IE’s innerHTML problem
How do you remove content from an element that’s already been added? The fastest way is to use innerHTML and set it to an empty string. Boom! The content is now gone. This is much faster than going through and removing each child using removeChild(). But there’s a problem with this approach in Internet Explorer. Try doing the following:
- Create an empty
<div/>element with a background color. - Insert some content dynamically (text, elements, whatever you’d like).
- Remove the content using
innerHTML.
What I expect to happen is for the <div/> to become invisible (technically, 0 pixels in height) because there is no content holding it open and a <div/> element has no height specified by default. In IE, the content is removed but the height of the <div/> does not go to 0; Firefox and Opera behave as I expected (sorry, don’t have Safari handy to test at the moment).
I remember a time when I used to have to code around bugs in Netscape Navigator, funny how things have been reversed now.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of Yahoo!, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




20 Comments
Safari behaves as expected, just tested it out. What was your workaround?
Andrew Herron on November 9th, 2006 at 9:40 am
Which IE version are you using, or is it universal to the browser?
Kevin on November 9th, 2006 at 10:39 am
For the past year or two, I’ve quietly proclaimed that Internet Explorer is the new Netscape Navigator 4. I wrote an article with that title and its sitting somewhere on my hard drive… I think I’ll dig it back up.
Jeremy on November 9th, 2006 at 11:02 am
Andrew - thanks for checking that out. I haven’t found a workaround yet. I was able to remove the contents using removeChild() multiple times and then set the height of the <div> to 0, but I don’t really like that approach. Still toiling away at it.
Kevin - I’ve confirmed that this happens in IE6 and IE7.
Nicholas C. Zakas on November 9th, 2006 at 1:15 pm
Nicholas - So you actually had to set the height of the div to 0 even when using removeChild?
Andrew Herron on November 9th, 2006 at 1:42 pm
Andrew - Yes, in my tests, using removeChild() alone didn’t do the trick, I actually had to set the height to 0 (setting the height to 0 when using innerHTML did nothing).
Nicholas C. Zakas on November 9th, 2006 at 1:43 pm
Something I noticed, though I’m not sure on the relevance:
When the div has nothing in it, FF correctly shows the offsetHeight as 0, but in IE, it shows it as 24.
Setting the height of the element will show in the offsetHeight, but when I set the height to 0 in IE, it shows 19, which is the height of the div when you add content.
Andrew Herron on November 9th, 2006 at 4:37 pm
What version of IE are you using when it the <div/> shows as 19? I remember IE 6 had this problem, but I thought it was fixed in 7.
You have to set font-size: 0px (or maybe line-height: 0px) to get the box to go below 19 pixels. I’ll have to rummage through my old CSS files to see if that’s the correct hack for that problem.
Jeremy on November 9th, 2006 at 5:43 pm
I’m not completely sure, but I heard about a "hidden" IE attribute named hasLayout, that IE uses to determine if some element’s content needs to be redrawn each time the css layout changes (or when there are changes in the page body). That property has default values depending on the type of element, but as a workaround one can set several CSS styles to the element to have it get hasLayout = true. I myself had had many problems with the redraw of background colors in floating divs, that dissapeared when doing this…
I will make some tests and then I’ll post my conclusions…
Look at… http://www.satzansatz.de/cssd/onhavinglayout.html
Regards.
Emilio on November 10th, 2006 at 2:34 am
The next code without the styles
position:absolute; (for the div)
and
display:block; (for the div’s parent, ie. body)
reproduces Nicholas behaviour, but with the lines the behaviour is correct!
<html>
<head>
<style>
#mydiv {
background-color: yellow;
position: absolute;
}
body {
display: block;
}
</style>
<script>
function doit() {
document.getElementById("mydiv").innerHTML = "pepepepe";
setTimeout(hideit,5000);
}
function hideit() {
document.getElementById("mydiv").innerHTML = "";
}
</script>
</head>
<body onload="doit();">
<div id="mydiv"></div>
</body>
</html>
Emilio on November 10th, 2006 at 2:51 am
Emilio - Your example doesn’t actually solve the problem, you’ve just moved the element to be absolutely positioned, which causes a different behavior. My example has the element statically positioned, which is where the problem occurs. The layout I’m working with can’t be absolutely positioned, so this won’t help.
Nicholas C. Zakas on November 10th, 2006 at 1:22 pm
Nicholas, how about a small testcase (small enough to trigger this bug)?
The following works for me (yes, its not innerHTML, but that is obviously a bug in IE):
<div id="myDiv" style="background-color:red">ie sucks</div>
<script>
var oDiv = document.getElementById("myDiv");
while(oDiv.hasChildNodes())
{
oDiv.removeChild(oDiv.childNodes[0]);
}
</script>
José Jeria on November 12th, 2006 at 5:51 pm
Jose - that is basically the test case I’m using, however, try inserting the contents of the <div/> using JavaScript instead having it inline. Then you’ll see the same problem.
Nicholas C. Zakas on November 12th, 2006 at 6:01 pm
As long as innerHTML is not used for either adding or removing it will work fine:
var oDiv = document.getElementById("myDiv");
oDiv.appendChild(document.createTextNode("testing"));
while(oDiv.hasChildNodes())
{
oDiv.removeChild(oDiv.childNodes[0]);
}
Seems like innerHTML is adding an empty text node or carriage return that cannot be removed.
Adding oDiv.innerHTML = "" after the while loop above will make the red come back.
P.S How about making this textarea just a tiiiiiiiiny little bigger?
José Jeria on November 13th, 2006 at 3:48 am
Nicholas, I don’t fully understand your point.
If you dinamically add contents to a static positioned div styled with a background color, then the div seems to appear in the page. After, when setting it’s innerHTML = ” the div remains in place with its background color… In my opinion, the bug here is that the background-color should be shown from beginning (or you can think that the bug is IE causing the div to have a height by default… Actually, it has height=auto and that appears to be 18 pixels)
If you test the same case styling the div with, for example, zoom : 1 (thus causing it to have hasLayout = true) (IE specific) then you will see that the div shows the background color before content was really added to it. That is, the hasLayout = true, has made the div to render correctly(?!) on screen always.
So, the question is simple: Why not to set display = none to hide a static element and save its space on screen? or visibility = hidden if you want to let it ocuppy its space in the layout?
Emilio on November 13th, 2006 at 4:07 am
Oh, one last thing, note that the "setting-the-elements-height-or-whatever-to-zero" work-around will not work in quirks mode (if you for some reason use it).
José Jeria on November 13th, 2006 at 4:27 am
This one is a bit tricky, but finally uses innerHTML and works!
<html>
<head>
<style>
#myDiv {
background-color: "red";
}
</style>
<script>
function doit() {
document.getElementById("myDiv").innerHTML = ‘fool’;
setTimeout(hideit,2000);
}
function hideit() {
var elm = document.getElementById("myDiv");
elm.style.display = "none";
elm.parentNode.innerHTML = elm.parentNode.innerHTML;
elm.innerHTML = ”;
elm.style.display = "block";
elm.parentNode.innerHTML = elm.parentNode.innerHTML;
}
</script>
</head>
<body onload="setTimeout(doit,2000);">
<div id ="myDiv"></div>
</body>
</html>
Emilio on November 13th, 2006 at 9:04 am
PS: Maybe a wrapper function comes in place… Assigning the parent node innerHTML to itself causes IE to really apply node style changes.
Emilio on November 13th, 2006 at 9:11 am
Emilio - the IE rendering is incorrect. When a block-level element with no content has an automatic height, it should be 0 pixels high. Setting the display to "none" does have the same effect, but the point is that IE is not behaving correctly.
Nicholas C. Zakas on November 13th, 2006 at 2:26 pm
I was having this same problem. I ended up using the outerHTML property to alter (or actually delete) the entire div, and the whitespace disappears. Of course, this broke in FireFox, so I kept my innerHTML in there:
document.getElementById(theDiv).innerHTML=”;
document.getElementById(theDiv).outerHTML=”;
The problem with this method is that once you set the outerHTML to null, you have wiped out the div, so cannot use its functionality again without a page refresh. Worked for what I needed, though =)
ilana on April 26th, 2007 at 3:52 pm
I’m facing the same problem of innerHTML property in one of my dynamic client rendering scenarios. I just wanted to know whether is it possible to use the DOM technique of recreating a new div and adding element using appendChild method and create the div at the very same location where the last div resided in HTML.
Talha Yousuf on September 12th, 2007 at 9:45 am