Swearing Off Hacks with Conditional Comments

A hack, in CSS parlance, refers to exploiting a CSS parsing bug unique to a particular user-agent to deliver alternative style rules or declarations to that agent, usually in order to compensate for some rendering bug also unique to the targeted agent. In plain English, a hack means using one bug to correct another. CSS hacks are often (and perhaps more accurately) referred to as filters, since the idea is to filter out the buggy browser and serve it corrective rules while more compliant browsers are allowed to render the proper CSS.

For a ubiquitous example, Tantek Çelik‘s famous Box Model Hack utilizes an oddball parsing bug in Internet Explorer for Windows. When IE/Win runs up against that bizarre cluster of slashes in the middle of a rule, it is tricked into thinking the style rule has ended and stops processing. Other browsers keep rolling right through the hack and process the declarations that follow, overriding the earlier value with the one you actually want them to render. Some other common CSS hacks follow this bug-for-a-bug principle, such as the commented backslash hack for IE/Mac and the underscore hack for IE/Win, to name two.

The hope is that, should a future version fix the parsing bug that comprises the filter, they would also fix the original CSS bug that was being compensated for. It demands a certain amount of finger-crossing faith in browser manufacturers (especially MicroSoft). History has taught us that this faith is frequently misplaced, so such hacks/filters are not to be trusted long term. If a version comes along that fixes only one of the symbiotically paired bugs the hack breaks and a new solution must be found.

A vintage photo of a man speaking with the driver of a taxicab

But CSS hacks are inherently bad. They’re sloppy, unreliable, potentially harmful, and should only be used as a last resort. Hacking means the deliberate introduction of faulty CSS. I’ve always felt a little dirty when I’ve included hacks in my CSS, as if by exploiting a flaw for a righteous purpose I legitimize that flaw’s existence, and I don’t like living in fear of the next service pack. So from this day forward I shall no longer hack around IE (I may still have to occasionally hack for other browsers, but that’s another post). Henceforth I’m using conditional comments instead, and so should you. Peter-Paul Koch has been dishing this punch for a long time, and with IE7 (the real one) just around the bend, all those messy hacks could come back to bite us.

Anatomy of a Conditional Comment

If you’re just joining us, conditional comments were a proprietary feature introduced in IE5 for Windows — which has thus far not been adopted by any other browser — allowing developers to easily delineate segments of HTML to be delivered only to certain browsers. Here’s how a conditional comment is formed:

<!-- [if IE]>
contents go here
<![endif]-->

The comment is conditional in that it can be structured as a semi-Boolean argument, applying only if the condition is true. The argument above simply says “if the user-agent is Internet Explorer process the content of this comment, otherwise ignore it.” All other browsers, including any non-IE browsers that may some day support conditional comments, will treat the contents as a normal comment in HTML, and will not render it. Versions of IE can be more specifically targeted by extending the condition with the version number: [if IE 5]. Minor versions are targeted with decimals: [if IE 5.5].

The basic list of argument operators is:

  • [if IE] – all versions of Internet Explorer for Windows
  • [if IE X] – only version X (where X is a version number)
  • [if lt IE X] – versions less than (but not equal to) X
  • [if lte IE X] – versions less than or equal to X
  • [if gt IE X] – versions greater than (but not equal to) X
  • [if gte IE X] – versions greater than or equal to X

Any of these can be turned into a not argument with a bang (!), but the real-world usefulness of this is limited. Since [if !IE] (if not IE) would only be read by IE anyway, what does that actually accomplish today? Unless (or until) other browsers integrate support for conditional comments they’re only good for targeting IE/Win, not excluding it. One obvious and currently practical use for a not-condition would be to exclude one version while the commented styles are delivered to all other versions of IE/Win, and only IE/Win. Example: [if !IE 5.5] (if not IE 5.5.) would be processed by all versions of IE/Win except version 5.5, while rightfully ignored as a comment by all other browsers.

Upside

Conditional comments are still a sort-of hack, but with one important distinction: they are a feature, not a bug. Using comments to deliver alternative CSS to IE/Win does not require dependence on bugs or browser quirks, and the contents of the comment can remain well-formed and valid. Since a particular version (or range of versions) can be specified, your corrective CSS can be delivered only to not-to-be-updated, known-to-be-buggy versions of IE and any future non-buggy releases can receive the regularly scheduled styling. Properly used, conditional comments are future-proof. An added benefit is that all your corrective styles can be tidily grouped together or relegated to their own external style sheet, leaving your primary style sheet unsoiled.

Downside

Of course, any time you delve into browser-specific CSS you’re complicating your site and making future modifications more strenuous. Conditional comment filtering is also difficult to test and debug, unless you have several Windows boxen laying around running different versions of IE. If you’ve installed multiple versions of IE on a single copy of Windows the comments will be processed based on the latest installed version so those [if IE 5] arguments fail in the presence of IE6. This can be easily dodged by doing your local IE5 testing without the comments in place, serving unfiltered CSS until you get it just right. Because conditional comments are HTML they do require a bit of extra markup as opposed to a CSS hack that could appear only in the style sheet. And of course all of this applies only to IE for Windows, bugs in other browsers may still require unpleasant hackery.

Update: 1.26.2006 – As pointed out by Adam Messinger in a comment on a completely unrelated post, it is now possible to test conditional comments on a single Windows box with multiple versions of IE installed. The process involves some hacking of the Windows registry, so is not for the faint of heart. Position Is Everything has the scoop.

Practical Use

Conditional comments can appear anywhere in the HTML document, but in the case of CSS filtering it belongs in the header. If you’re linking/importing external style sheets, as long as the commented one comes last it will trump the previously linked style sheets thanks to the cascade (so long as the IE-only rules equal the bug-inducing rules in specificity).

Here’s an example:

<!-- [if lt IE 6]>
    <link rel="stylesheet" type="text/css" media="screen" href="/css/ie5styles.css" />
<![endif]-->

The first-linked style sheet is where all the general rules live, and it’s still read by the target buggy browser. The second style sheet hides in the comment and is only seen by the target. As for what appears in those two style sheets, define as much as possible in the primary sheet and the IE sheet need only contain any alternative values to overcome bugs. Here’s an example that would normally require the Box Model Hack, but the hack can be avoided with a conditional comment:

<!-- [if lt IE 6]>
<style type="text/css" media="screen">
#somebox { 
    width: 500px; 
}
</style>
<![endif]-->

Note that the commented rule only carries the new width, rather than repeating the entire rule. Since even the buggy versions can render the rest of the rule just fine, redeclaring all the properties is redundant and would only make things harder down the road (if you wanted to change the background color of the box, you’d have to make that change in two places). This is part of smart hack management — only correct the bits that need to be. You’ll also notice that this example uses inline rules in a <style></style> element, just to show you how it’s done. The entire element is repeated with the opening and closing tags because that element carries its own format for comments (/* */) and HTML comments within <style></style> are not handled. I learned that the hard way.

So far I’ve only been talking about conditional comments used in place of CSS hacks. Some more of IE’s shortcomings can be sidestepped in this manner as well. Want to use 24-bit PNGs with alpha transparency for your background images? Go right ahead, and just swap them with 8-bit versions for IE6 and lower. Want to deliver some superficially enhancing DOM script to IE only, but don’t trust old-world browser sniffing? Stash that script in a comment. And with a little nefarious creativity you can even deliver a completely different design to IE than other browsers will see.

Conditional comments have been part of IE/Win for years but have only recently become well known and popular, and as more designers adopt them we’ll gradually strip out and retire the hacks we’ve been using for the last few years. Of course, in a perfect world there would be no need to split up the CSS we send to different browsers, and such non-standard proprietary markup would not exist. Our world is not yet perfect, but perhaps some day this technique too will be as old-school as the nested tables of years past and the CSS hacks of more recent memory. But until IE5 and 6 are finally, truly dead their bugs will remain with us for years to come. Best get used to it.

2 comments

  1. Can conditional comments sit inside the CSS file? It would be nice to move all of my ie hacks to the end of the file rather than import them as an additional style sheet.

  2. Alas, Ted, conditional comments are HTML, not CSS. They have to go in the document. The extra markup is the biggest drawback in my book.

    If your site uses some sort of template so the document header is contained in one file (which is then included on every page of the site) it’s pretty simple to add a comment in that one place, and then to remove it at some time when it no longer becomes neccessary.

    However, if you’re maintaining pages by hand I’d still opt for CSS-only hacks over conditional comments. And in that case I do recommend moving all your hacks to the end of the file and grouping them together, rather than leaving them scattered throughout a style sheet.

Comments are closed.