css, 404s and safari 3

If you've been following this blog, you might already be aware that I'm in favor of conditionial css targeting, a method that allows separate blocks of css to be served to specific browser(s/versions). This is already possible for IE, but not for other browsers (unless you are using some obscure css hacks). Last week we hit a different way to accomplish this for Safari 3, completely by chance and hardly recommended practice, but still worth an article.

what happened

Earlier this week we launched a big update for one of our sites. We updated the design, redid some of the html and css and made the whole deal a bit more consistent. Everything went according to plan, until it actually went live and we checked the result in Safari 3. Some very weird styling issues popped up that weren't to be seen in any other browser. Styling rules that weren't even in any of our stylesheets. Strange behavior which demanded a quick solution.

After some digging we finally found the culprit. One old css file was still referenced in the html, but was deleted on disc as it had become obsolete. The website was running on JBoss, which returned a 404 error and a JBoss 404 error page. This error page contained a style block in the head of the html, which Safari 3 used for actual page styling. Something that baffled us all.

further investigation

We did some more testing and the results were actually quite surprising (but not at all strange if you think it through). It turns out that any browser reacts this way when served a html page containing an inline style block, rather than a css file. Since you stated that the referenced file is a css file in the html already, it just takes your word for it and tries to parse whatever you send its way as css. As an extension, this goes for whatever file you serve it.

This means that the first string of html tags (<html><body>...) until the first "{" within the style block is considered to be the first selector. Obviously, this selector won't hit any element on your page as the syntax of this first selector is complete gibberish. But after this first rule is closed down (the first "}" encountered), what follows is a valid, regular block of css statements ready to be executed and applied if not overruled by any other css rules later on.

This explains where Safari 3 was getting its styling, but still leaves us in the dark about the other browsers ignoring these styles. Where we stand now, we assume the reason lies with the 404 message that is sent along with the 404 page containing these styles. Apparently all other browsers take this 404 message as a cue to abandon the file. Yet Safari 3 seems to ignore the 404 message and still tries to make the best of it. We haven't been able to fully test this, but that's as far as we got and at this time seems to be the only logical explanation left.

exploits and conclusion

While this is most definitely a bug, it can be exploited to serve a specific set of styles to Safari 3. All you need to do is make sure you send a 404 error with a specific error page containing the Safari 3 specific files. I would never ever ever recommend doing this, but in some extreme cases this might come in handy.

This is not the reason for writing this article though. The fact that html pages can be served as css without error is new to me, and so is the assumption that Safari 3 (it's already fixed in 4) ignores the 404 error message. It's a pretty extreme use case and most people will probably never hit it, but if you do, at least you now know what is happening. And of course, the solution is very simple. Either you make sure you always override the styling of the error page, or you simply remove the reference to the non existing file.