Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Usability

Web Design Reference Guide

Hosted by

Taming The Browsers: CSS Hacks

Last updated Oct 17, 2003.

By Dave Shea

The traditional method of fixing browser bugs is finding some way to ensure a specific browser will exclusively render a snippet of CSS that other browsers will not, or exclude a specific browser from rendering a snippet of CSS that other browsers will. Since CSS has no approved method of doing this, it has been left up to individual authors to discover alternate methods. Hence, the rise of CSS hacks. A great basic primer on CSS hacks and long-term management is available in Integrated Web Design: Strategies for Long-Term CSS Hack Management.

A few CSS hacks offer the ability to selectively import browser-specific CSS files only in the browsers that need them. Those are the ones we’re most interested in. All other browsers will ignore the extra CSS files, which means the files themselves can be free of any further workarounds. It’s like saying, “You’re running Internet Explorer 5, so you get this file, but all other browsers will ignore it.”

IE5 Filters

Created by Tantek Çelik, the IE5 filters are designed to import CSS files in various versions of Internet Explorer 5, while all other browsers ignore them. We can place all of our IE5-specific CSS in these files, without further hacks, and be assured that no other browser will attempt to render this code.

For example, if you have to correct for IE5.x/Windows’ misinterpretation of the box model, you don’t need to use the Box Model Hack anymore. You would use the IE5.x/Windows Mid Pass Filter and place your workaround in the external file. So, where you might once have had code that looks like this:

Contents of main.css:

div.content { 
  width: 400px; 
  voice-family: "\"}\""; 
  voice-family:inherit;
  width: 300px;
}

You’d instead leave the width intended for all other browsers (300px) in the main CSS file, main.css, and move the width intended for IE5.x/Windows into its own CSS file, ie5win.css. Then, insert the Mid Pass Filter into the main CSS file in order to import ie5win.css when needed.

Contents of main.css:

div.content {
  width: 300px;
}
@media tty {
 i{content:"\";/*" "*/}} @import 'ie5win.css'; /*";}
}/* */

Contents of ie5win.css:

div.content {
  width: 400px;
}

Obviously, with a single hack like this it seems like more trouble than it's worth, but having an external file to dump all your IE5-specific code keeps your main style sheet clean, and it also means that no other browser needs to download this targeted CSS. And, it’s easier to manage in the long run thanks to the clarity of having all your IE5 hacks in one place.

Now, what about IE5/Mac? It has its own filter, which you may use independently of the IE5.x/Windows filter, or in conjunction within the same CSS file:

Contents of main.css:

/*\*//*/
 @import “ie5mac.css”;
/**/

div.content {
  width: 300px;
}

@media tty {
 i{content:"\";/*" "*/}} @import 'ie5win.css'; /*";}
}/* */

Unfortunately, because of the way the two filters work, we can’t place them near each other in the file. An @import statement rightly occurs before any other style in a CSS file, which is why the IE5/Mac filter goes at the top. But if the IE5/Windows filter were at the top, other browsers would ignore any style that came after it due to the parsing error it exploits. It, and it alone, needs to occur at the very bottom of the CSS file.

You could choose to move all style out of your main style sheet. If the file you link to from your HTML is nothing but a series of @import statements, then you could bunch the browser-specific imports together at the bottom of the file. The only catch is that they need to occur in a very specific order: IE6 first, IE5/Mac second, and IE5/Windows last. View the files at the end of this article for a demonstration of how this system works.

There are four IE5 filters in total. One exists for IE5/Mac, one exists for IE5.x/Windows, and there are two more specific filters that will exclusively target IE5.0/Windows and IE5.5/Windows, respectively.


IE5.x/Windows Mid Pass Filter

IE5/Mac “Band Pass” Filter

IE5.0/Windows “Band Pass” Filter

IE5.5/Windows “Band Pass” Filter

IE6 Filter

We have two different ways of giving IE6 a browser-specific style sheet, one uses CSS hacks, and one uses a proprietary, IE-only feature. Let’s talk about the hack first.

The * html hack has been around for a while, and it allows us to serve CSS only to IE/Windows:

Contents of main.css:

div.content {
  width: 50%;
}
* html div.content {
  width: 100%;
}

IE/Windows will size the div in question to 100 percent; all other browsers will render it at 50 percent width. Since there’s no equivalent to the Mid Pass filters for IE6, we need to use the * html hack in order to make sure that IE is the only browser to apply our rules.

First, we’re going to import ie6win.css using a normal, unfiltered @import statement in our main CSS file:

Contents of main.css:

@import url('ie6win.css');
div.content {
  width: 50%;
}

Unlike the IE5 filters, all browsers will load this external file. This is why within ie6win.css, all rules must be preceded by the * html hack, so that Firefox and others will ignore them:

Contents of ie6win.css:

* html div.content{
  width: 100%;
}

What astute readers may have noticed by now is that since ie6win.css is loaded by all browsers, and the * html hack applies to IE/Windows and not IE6/Windows exclusively, IE5 will also apply the rules in this style sheet. In some cases, you will want the same hacks to apply to both browsers, but not all the time. This is a problem.

Fortunately, we can rely on CSS specificity to help us overcome it. If we place the IE6 import before the various IE5 imports, overriding anything styled in ie6win.css is as easy as duplicating the selector, then changing any property that needs to be overridden. For example, say you need to adjust margins on your sidebar in ie6win.css, but don’t want IE5/Windows to render it:

Contents of ie6win.css:

* html #sidebar {
  margin: 10px 300px 10px 0;
}

You’d need to also duplicate the rule in ie5win.css and then change the margins in that file back to their intended IE5/Windows value:

Contents of ie5win.css:

* html #sidebar {
  margin: 0 500px 0 0;
}

It causes a bit of extra work, granted. There is a slightly easier way to do this involving a proprietary feature of IE called conditional comments, which has the added advantage of being officially sanctioned by Microsoft.

Conditional Comments

Conditional comments sit within your HTML file and function very similarly to CSS IE5 filters. You can use simple conditional logic to test for different versions of IE, and then send each arbitrary HTML if it meets the conditions. In our case, we’d like to selectively pass different CSS files to versions 5.01 through 6:

<!--[if IE 5.0]>
  
<![endif]-->
<!--[if IE 5.5]>
  
<![endif]-->
<!--[if IE 6]>
  <link rel="stylesheet" href="ie6win.css" media="screen" />
<![endif]-->

Because they’re enclosed in HTML comment syntax, they validate, and no other browser parses them. So conditional comments seem like the perfect fix, and Microsoft even recommends we use them. Why bother with the hacks at all, and why am I not whole-heartedly endorsing them?

Unfortunately, conditional comments aren’t perfect in all scenarios. You need to place the comments within your HTML instead of your CSS, which makes the links themselves non-cacheable. Negligibly so in most cases, but it may be an issue for some. More harmful is when you're running multiple versions of IE on one PC—you will not be able to test sites that use conditional comments. All versions will identify as the most recent version—IE6 most likely, until 7 is released—and it makes testing impractical.

So, we have a conundrum. Microsoft’s IE team has announced that in IE7 most of the current IE hacks will no longer work. Microsoft recommends conditional comments as the way forward. But, unless we have multiple computers running different versions (or, at the very least, virtual machines using a program like Virtual PC), we can’t test on anything more than the most recent version of IE if we go that route. What to do?

Fortunately, all current hacks will continue working in existing browsers; the system I’ve outlined above will work just fine in IE6, even after IE7 has been released, and you’ll be able to continue testing your work on more than just the latest version. You can use conditional comments to target IE7 specifically if need be, although it looks as if many of the CSS bugs we currently need to hack around will be fixed for IE7.

More information on the IE7/conditional comments issue is available at the Web Standards Project.

Other Browsers

This article has been very heavily focused on working around IE’s shortcomings; it simply needs the most attention. How would you extend this system to serve other browsers their own specific CSS files in the same manner? Unfortunately, there’s no easy answer for this. To the best of my knowledge, none of them have any form of filtration akin to IE’s conditional comments, and the W3C hasn’t recommended a method.

Most of the time, this isn’t a problem, but there are instances where you will experience inconsistencies between non-IE browsers. For instance, current versions of Safari offer very little control over form elements, instead using OS X defaults; this can be a problem when it comes to harmonizing input elements with background images, or making use of precise widths.

This isn’t a problem with a solution at the moment, and this whole issue hints at a fundamental assumption that CSS makes, which is highly problematic for page authors. The ideal is that all browsers will render elements consistently, so there is no need to write code that differentiates between them.

In practice, however, it’s a much different story. We all know by now that browsers are not created equal. And, unless the Web stops evolving, they never will be. One or two will always be behind the rest. And, so, in the vacuum of official recognition of the problem, we see solutions like CSS hacks pop up from page authors, the people who get stuck coding in these circumstances.

Maybe at some point in the future there will be a perfect browser management system that doesn’t involve tricky hacking to work outside the boundaries of officially-sanctioned solutions; until then, we have a crude solution that does the job.

A functional example of the browser-specific styling method outlined in this article can be downloaded below.

The file available for download below is a slight modification to the previous file. This file places all CSS in secondary imported files to demonstrate how the browser-specific imports may be grouped together.