Someone once told me that WWW stands for World Wide Wait. But when the page is held because the browser waits for a Google Ad to come in, that’s really annoying. I didn’t want that to happen in my site.
So here’s the story about how to have the page displayed first, ads later. One may argue that you want your money machine up (ha!) before giving away the goods. One could also argue that the ads coming in late will draw more attention. I say: A slow site is like no site.
And as with any story, the solution comes in the end. If you want to know who the killer is, and don’t care about the drama, just skip to the end.
Trial #1: Absolute positioning
The idea was that if the browser doesn’t need to know what’s inside the ad box, it will go on rendering the page. Since an absolutely positioned section is out of the flow, and won’t change any other part’s placement, I hoped that the browser would be smart enough not to wait for the ads. Or stupid enough to overlook the inconsistency in scripting. I was wrong.
Anyhow, this is the code I used:
The outer DIV allocates the necessary space on the page. The inner DIV is absolutely positioned, so no matter what comes in there, everything else will remain in place.
What really happened: IE6 went right on with the rest of the page, Firefox still waited for the ads to load. Even though IE played it nice this time, it’s actually a bug in IE.
This way or another, the problem remains. I mean, even Microsoft will fix this bug some day.
The idea is simple. If the Google ad code appears just before the closing </body>, the browser must be pretty boneheaded to wait for it. So now the trick is to get the ad in the right place.
There are scripts out there which claim to do that, but they don’t rely on any standard. And getting a block of ads in the wrong place is too bad to risk.
And I haven’t even mentioned what happens when the page is resized. Unless all surrounding elements are nailed in place with absolute positioning, bad things can happen…
Anyhow, this method didn’t fit my case. I dropped it.
Trial #3: Hijacking document.write()
One widely proposed solution is to hack document.write(), which Google uses to implant the extra HTML. I don’t like it very much, because it’s well, hacky. But I tried. And then I saw what the script in show_ads.js produces:
<script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"> </script> <script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"> </script> <script>window.google_render_ad();</script>
So show_ads.js writes a script that loads other scripts? Doing what? Call other?
This was just enough to scare me off. If hijacking means to recursively run scripts loaded by scripts, there’s a good chance to really mess things up. So I gave this idea up as well.
Trial #4: Moving the DOM element
This is the way to do it. Let the browser reach the ad segment at the end of the document, and then manipulate the document tree, moving the element to its right position. This is pretty intrusive, and it turns out that it pushes the browser’s tolerance to the limit.
But first, let’s look at the code. It has two parts. First, we put this where we really want the ads:
<div style="position: relative; height: 620px; width: 200px; overflow: hidden; "> <div id="googletarget" style="position: absolute; top: 0px; left: 0px"> </div></div>
That’s pretty much like what I did in trial #1, with two important differences: The google ad isn’t here, of course, and I’ve given the inner DIV an ID, so I can target it later. Absolute positioning is still important, because I don’t want the page to flicker when the ad comes in.
Then, at the end of the document (before closing </body>) we have:
That rings an old bell too. It’s exactly like the original script, now embedded in other DIVs and with an extra script snippet, which moves the ads to their right position using appendChild(). W3C is very clear about that appendChild() never duplicates a node, but moves it in case it’s already placed in the document tree.
And the DIV, to which the ads are loaded into, is wrapped by another DIV which is set to “display: none”. This makes them invisible in their original position, so nothing flickers at the bottom of the page and the scroll bars don’t get crazy. And even better, if the appendChild() fails (because the browser is old or primitive), the ads remain invisible. Which is rare enough to neglect businesswise, and harmless in terms of how badly we’ve messed up the page.
In IE6, it was necessary to set the display mode back to “block” after moving it. That’s what the line after the appendChild() is for.
By the way, “visibility: hidden;” wasn’t enough, because the Google data contains an IFRAME, which doesn’t respect the external DIV’s visibility status.
And in the extreme case, in which the browser doesn’t respect the “display: hidden” attribute, we will have some ugliness at the bottom of the page. Functionally, it’s still harmless, and graphically it’s not so bad compared with what such a browser’s user sees every day.
So, this looks like a bulletproof solution. Of course it worked on any fairly updated browser I tested with. What could possibly go wrong?
The answer came to me when I tried in on an Mozilla 0.99 (seven years old). Don’t think I’m using it for myself, but testing on a steam engine is a good way to find weak spots. In our case, moving the ads around caused the browser to display a blank page. All was fine just before the call to appendChild(), but then the page went blank, and the browser started to behave strangely.
This is bad news. I’m trying to make a page load slightly faster, and I might make it unloadable (to some) instead. Even if I don’t believe that someone really uses a browser from 2002, a new, cutting-edge and somewhat buggy browser might fall in the same hole.
The problem, as it turned out, is that the element I move around consists of scripts. Mozilla 0.99 executes the script once when it’s loaded, and once again when it’s moved. Modern browsers execute the script once. IE6 is in the middle: It indeed runs the script once, but loads it twice. Not harmful to the user, but this indicates that moving a script around is not an issue of the past.
It also looks like there was an issue with appendChild() and scripts around the development of Firefox 3.1, but given the relatively little attention it got (and the fact that the relevant remark in the docs has vanished), I suppose this is a non-issue.
To see how the browser behaves, I wrote a small snippet:
<div id="taker"></div> <p>Hello, world</p> <div id="loser"> <div id="node"> <script> alert("Script running"); document.write("I was first!"); </script> </div></div> <script> var node = document.getElementById("node"); alert("Now swapping"); document.getElementById("taker").appendChild(node); </script>
The idea is that the two rows swap places by virtue of appendChild(). The “script running” alert should appear only once, of course. On Mozilla 0.99 it popped up twice, and the page ended up with “I was first” written before and after “Hello world”, which sort-of explains why nothing worked with Google ads. Other browsers I checked, including Konqueror 3.0.0 from 2002 ran the script once, as expected.
The solution I picked was appendChild(), of course. But I also realize that moving around an element which contains a script pushes the browser to its limits. On the other hand, AJAX web sites are becoming increasingly popular, so browsers are more and more likely to support this properly in the future.
For my own use, I’ve decided to do this trick only on browsers I’ve tested. This is possible since the page is produced by a server-side script, which checks the browser version. This will make the page load slightly slower on non-mainstream browsers, but on the other hand, guarantee that the page loads at all.