CSS Hacks

01 January 2003

Reader beware: this article is a bit old!

OK, so you’re happily writing some CSS for your structured X/HTML. You get some nice effects in IE6, then test the page in Mozilla and find that widths are different, and you have all sorts of problems. Or, you get it working in Mozilla, try it in IE, and it doesn’t work.

Usually, it’s due to different (and incorrect) box models. Mozilla tends to display the CSS as it should be, but it does have the odd bug in it’s system. IE5 and IE5.5 have some CSS problems, and so some things would look different in these browsers compared to what they look like in, say, IE6. So, we want our CSS to look similar in these browsers:

I have combined IE5 and IE5.5 above as they both suffer from very similar CSS issues. IE6 has fixed a lot of problems, but it’s still far from perfect. Mozilla is very, very good, but as it has a different (and more correct) box model, it often renders the CSS differently to IE6. Note that Netscape 6 uses the same Gecko engine, and is infact just an earlier version of the current Mozilla release.

There are a couple of little CSS hacks that can be used to make the same (fairly simple) CSS work in all of the above browsers.

IE5/5.5 CSS parser bug

At first sight, a CSS parser bug seems to be a nightmare. However, it can be a blessing in disguise sometimes. If you add the following properties to your definitions:

voice-family: ""}""; 

Then the parser will close that CSS rule. Suppose you wanted to show the ‘hand’ cursor for an element other than a link (let’s say an image tag). You could do this:

img { cursor: pointer }

This is the valid value of the cursor definition to use. However, IE5/5.5 doesn’t use that value. They instead use the value hand. So, you could do the following:

img { cursor: hand }

But then, any other browsers (IE6, Mozilla etc.) would then not get a ‘hand’ cursor (as they use the valid value). You can take advantage of the IE5/5.5 parser bug by doing the following:

img { 
  cursor: hand; 
  voice-family: ""}""; 
  voice-family: inherit; 
  cursor: pointer; 

So, IE5/5.5 reads the first definition of this rule for the image tag. It makes a ‘hand’ cursor show when your mouse moves over images. Then, it reads the next two lines, and ends the rule with a } (as it should). It does’t even read the last rule.

IE6 or Mozilla comes along, and reads the first definiton of the rule. It changes the cursor to the hand value. However, as this is not a correct value in these browsers, it still shows the basic arrow. It then reads what we know as the IE5/5.5 parser bug. It is not affected by this bug, and keeps reading. The CSS that makes up the hack that we are creating also does not affect the style of the image element (or any element for that matter). So, it then gets to the final definition, and sets the value of the cursor definition to pointer. Now, a hand is shown in all browsers.

There you have it. You have a way of separating IE5/5.5 definitions from IE6 and Mozilla definitions. All browsers will show a ‘hand’ cursor now. Job done :-)

IE6 support

Even though Microsoft added a lot more when they created IE6, it still isn’t as good as Mozilla for its CSS support. Using the above method, we can separate IE5/5.5 from all the newer browsers. However, what if we want to separate IE6 from the other new browsers (that may render the CSS differently)?

We simply take advantage of IE6’s lack of proper support, and confuse it a little. Say we do this:

#myElement { width: 100px }

But due to different box models, borders etc. in Mozilla it becomes too long (it seems to infact be 110px). We can do this:

#myElement { width: 100px } 
html>body #myElement { width: 90px }

IE6 will read the first rule, and set the width of my element to the value of 100px. It then reads the next rule, but the html>body part of the selector confuses it. Naturally, it skips the definitions in that rule.

Mozilla comes along, sets the width the 100px, as IE6 did. However, Mozilla supports more CSS, and so understands the selector for the next rule. So, it changes the width to 90px. This will fix the width problems we have been having.

Please, try to code your CSS without using any of these hacks. However, if you really, really need to use a hack to get it working better in another browser, then do so. It certainly beats using JavaScript to detect the browser, then load a custom stylesheet from there!