strapyourself.in and flouri.sh

Nesting document.write

September 23rd, 2007

Not a good idea - IE and Firefox treat differently

I'm not an advocate of document.write by any means, but it seems unavoidable when dealing with 3rd parties. Ad networks especially seem to rely on delivering ads using a remote script tag and document.write. They typically do not provide an alternative using the more modern and well defined XML DOM manipulation functions such as createElement and appendChild.

Let's examine two simple examples of using nested document.writes, and see how they are treated in both IE and firefox:

<div id="before_main_script">Before Main Script</div>
<div id="main_script">
 <script>
  document.write("<div id='before_sub_script'>Before Sub Script</div>");
  document.write("<scr"+"ipt>document.write('<div id="hello_div">hello!</div>');</scr"+"ipt>")
  document.write("<div id='before_sub_script'>After Sub Script</div>");
 </script>
</div>
<div id="after_main_script">After Main Script</div>

You can see how I escape the inside <script> and </script> tag so the browser doesn't think I'm closing the outside script tag. In both IE and firefox, this renders how you'd expect:

Output in both IE7 and Firefox2:

Before Main Script
Before Sub Script
hello!
After Sub Script
After Main Script

Firefox2 DOM using Firebug:

IE7 DOM using Internet Explorer Developer Toolbar:

Now let's make the example more complicated and watch things break down. All we've done is refactored the embedded script tag into an external script with a src attribute:

<div id="before_main_script">Before Main Script</div>
<div id="main_script">
 <script>
  document.write("<div id='before_sub_script'>Before Sub Script</div>");
  document.write("<scr"+"ipt src='/say_hello.js'></scr"+"ipt>")
  document.write("<div id='after_sub_script'>After Sub Script</div>");
 </script>
</div>
<div id="after_main_script">After Main Script</div>

Output in FireFox2:

Before Main Script
Before Sub Script
hello!
After Sub Script
After Main Script

Output in IE7:

Before Main Script
Before Sub Script
After Sub Script
hello!
After Main Script

IE7 DOM using Internet Explorer Developer Toolbar:

Unexpectedly, IE7 did not process the nested script tag as it was being written into the document stream, instead waiting until it had finished processing the parent script. As browser implementation goes, this approach should be easier, because you wouldn't have to save the running script context temporarily to being processing a new one, and finally resume the saved context. We've also tried the same code without the nested script tags, and this weird behavior goes away. Naturally, this can get you into serious trouble if you're including a remote script that defines certain variables which you make use of immediately!


You might be skeptical that this could ever become an issue in the real world. One of our clients had to generate some javascript to skin a 3rd party site to look like theirs, and they wanted to put double-click ads in. This requirement resulted in a javascript which executed a series of document.writes to skin the 3rd party site, including writing out a 2 inline script tags and 1 with SRC to doubleclick. The doubleclick script then used document.write to print out the ad. We first noticed the difference in placements of the ads in IE7 and Firefox, and ran the above tests to determine what the problem is. Here's how we solved it:

document.write("<scr"+"ipt src='/before_3rd_party.js'></scr"+"ipt>");
document.write("<scr"+"ipt src='3RD_PARTY_URL.js'></scr"+"ipt>");
document.write("<scr"+"ipt src='/after_3rd_party.js'></scr"+"ipt>");

I originally posted this article on ELC

Sorry, comments are closed for this article.

original design by gorotron ported by railsgrunt powered by mephisto