Wednesday, March 12, 2008

CSS tricks that target specific browsers

I've recently helped a client re-skin an existing webapp. Apart from changing the colors, images, fonts, etc one of the bigger changes was migrating layouts that used HTML TABLEs to Cascading Style Sheets (CSS).

Any good web designer will tell you the "proper" way to lay out web elements is to use DIVs and SPANs and CSS instead of TABLEs.

CSS, however, does have its challenges since different browsers render CSS differently.

Right now the three major browsers by market share are IE6, IE7 and Firefox 2. Firefox and IE7 render CSS pretty much the same way (more standards compliant), while IE6 often does its own thing. The good news is that if you can get a page to render the same in IE6, IE7 and Firefox then the page will probably look the same in other browsers such as Safari and Opera.

No matter what you try, however, it is sometimes impossible to use the same CSS for IE6, IE7 and Firefox. However, although it can get a little messy, there are some CSS syntax tricks you can use to apply specific styles to specific browsers.

Before we talk about those tricks, however, lets talk about the different rendering modes used by browsers.

Quirks mode and Standards mode

In the beginning Internet Explorer was playing catch up to the disruptive technology that was the Netscape browser. IE added many IE-specific features and only half-heartedly supported new web standards like CSS and XHTML. Netscape too was also slow to adopt the w3c standards. Eventually IE killed off Netscape. Microsoft was then left with a choice: Do they change IE to render according to web standards, thereby breaking many web sites that came to rely on the pre-standards way IE rendered, or ignore w3c standards?

Microsoft decided to support both. The old rendering was dubbed quirks mode while the new rendering was dubbed standards mode (sometimes called strict mode).

Similarly Mozilla, the successor to Netscape, also supports a quirks mode and a standards mode.

So how does IE and Firefox know which mode to render a page in? By default it is assumed a page should be rendered in quirks mode, unless the HTML 4+ or XHTML 1.0+ doctype appears at the top of the page, in which case the page will be rendered in standards mode. e.g.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Hello Title!</title>
<link rel="stylesheet" type="text/css" href="hellostyle.css" />
</head>
<body>
<div class="hello">
Hello Style!
</div>
</body>
</html>


Wikipedia has an excellent table showing doctypes and how they effect the rendering mode of various browsers.

To make matters more complicated IE7 is more standards compliant than IE6 but still not as compliant as it should be; in other words IE7 has an "almost-standards" mode.

For the upcoming IE8 Microsoft are still skittish about making IE more compliant and "breaking the web" that relies on existing IE rendering behavior, so they plan to have a quirks mode, an IE7 almost-standards mode and an IE8 standards mode. IE8 standards mode will be the default standards mode in IE8. To trigger IE7 standards mode in IE8 the web page must contain the HTML or XHTML doctype and an additional META tag specifying IE7. e.g.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Hello Title!</title>
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<link rel="stylesheet" type="text/css" href="hellostyle.css" />
</head>
<body>
<div class="hello">
Hello Style!
</div>
</body>
</html>


So, on to some CSS tricks.

Update: Joel has an opinion on IE8 and its standards mode. I wouldn't be too surprised if his prediction about the IE team reversing at the last minute the decision to make IE8 standards mode the default given the number of websites that currently look ugly in IE8.

Update 2: Yes, it looks like MS have broken the standards mode promise with the release of IE8 beta 2. Compatibility Mode is the default, and if a web page is marked as standards compliant then IE will show a "broken page" icon :(

Internet Explorer Conditional Comments

Introduced in IE5, conditional comments are an IE-specific hack to standard HTML comments that allow IE to render part of an HTML page if the specified version matches, while all other browsers will ignore what is inside the HTML comment.

For example:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Hello Title!</title>
<link rel="stylesheet" type="text/css" href="hellostyle.css" />
<!--[if IE 7]>
<style type="text/css">
body {
background-color: #00AA00;
}
</style>
<![endif]-->
</head>
<body>
<div class="hello">
Hello Style!
</div>
</body>
</html>


All browsers will read styles from the file hellostlye.css, while only IE7 will override the body background color.

While this can be useful, conditional comments only work inside HTML files. What would be more useful is conditional behavior inside CSS files or style blocks.

Internet Explorer: The Underscore Hack and the Asterisk Hack

Let's set up a CSS example.

Say we have an HTML file with the following contents:

hellostyle.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Hello Title!</title>
<link rel="stylesheet" type="text/css" href="hellostyle.css" />
</head>
<body>
<div class="hello">
Hello Style!
</div>
</body>
</html>


and a companion CSS file with the contents:

hellostyle.css

.hello {
text-align: center;
background-color: #FF0000;
*background-color: #00FF00;
_background-color: #0000FF;
}


If you are familiar with CSS you'll understand all of the syntax except for the "*" and "_" in front of the background-color properties. What do they do?

The CSS specs say that browsers should read any property names they know about and ignore any property names they don't know about. In the above CSS the spec compliant browsers know about a property named "background-color" but don't know about properties named "*background-color" and "_background-color".

To cut a long story short, the Internet Explorer CSS parser is overly aggressive at trying to discover the names of properties and will in fact ignore leading non-alphanumeric characters. From my testing this appears to be the case from at least IE5 onwards.

It became convention amongst web developers to used an underscore in front of property names when targeting CSS for IE, although any non-alphanumeric character will work. However, the CSS 2.1 spec made underscore a valid character in a property name, so IE7 specifically removed underscore from their aggressive parsing. From IE7 onwards web developers have been using an asterisk instead of an underscore when targeting CSS at IE, although any non-alphanumeric character will do. Interestingly, the removal of the underscore hack in IE7 allows you to target CSS at pre-IE7 (using underscore) and post-IE7 (using asterisk or some other non-alphanumeric character) browsers.

So with this background knowledge here is how the above CSS would be interpreted by different browsers:
  • Firefox, Opera, Safari and all non-IE browsers would correctly parse "background-color", fail to parse "*background-color" and "_background-color", and will set the background color of the div with class "hello" to red.
  • IE6 and earlier versions of IE will successfully parse "background-color", "*background-color" and "_background-color". The background color value will come from the last successfully parsed property, so the background color of the div with class "hello" will be set to blue.
  • IE7 and later versions of IE will successfully parse "background-color", "*background-color" but fail to parse "_background-color". The background color value will come from the last successfully parsed property, so the background color of the div with class "hello" will be set to green.
One final note on this IE leading non-alphanumeric character hack: It is invalid CSS so the strictest parsers will give you an error.

IE8 CSS Extensions

Microsoft have listed the CSS extensions available with IE8. The main change is that previous IE-specific extensions will now be required to be prefixed with '-ms-'. e.g. "overflow-x" now becomes "-ms-overflow-x".

Firefox CSS Hacks

There are plenty of CSS hacks for IE, but what about Firefox?

I've found one hack that allows you to target Firefox 2 or Firefox 3, but some versions of IE also pick up the CSS intended for Firefox. Extending our CSS file above:


.hello {
text-align: center;
background-color: #FF0000;
*background-color: #00FF00;
_background-color: #0000FF;
}

/* Target Firefox 3 */
.hello, x:-moz-any-link, x:default {
background-color: #FFFFFF;
}

/* Target Firefox 2 */
.hello, x:-moz-any-link {
background-color: #FF00FF;
}


In Firefox 2 the background color of the div with class "hello" will be pink, but strangely it will also be pink in IE5 and IE7 (they will pick up the last CSS property intended for Firefox), and blue in IE5.5 and IE6 (they don't pick up the CSS intended for Firefox).

If you find any Firefox CSS hacks that will only be applied to Firefox please let me know.

The closet thing to official CSS extensions for Firefox is here.

Other Browser CSS Hacks

http://www.webdevout.net/css-hacks contains a good summary of the known CSS hacks.

Useful Tools to test Browser Rendering

If you have IE7 installed but want to test earlier versions of IE then use Multiple-IE to install and test standalone versions of IE from IE3 to IE6.

If you have IE6 installed and want to use IE7 then try IE7s. Beware that, at the time of writing this blog post, pop ups and combo boxes don't work in IE7s.

Firebug is a Firefox add on that allows you to, amongst many other things, inspect and change CSS on-the-fly.

Internet Explorer Developer Toolbar provides similar functionality to Firebug for IE.

6 comments:

Less said...

Don't forget that Gmail and other email clients don't support CSS for various reasons. Tables still rule the day for email newsletters.

Robert Maldon said...

I'm sure tables will be used for layouts for a long, long time to come.

Gmail's "standard" view itself correctly uses tables just for the list of emails and divs/spans + css for everything else around it.

Thanks for the pointer, I'll have to look into if you can use css for the body content of emails. I suspect gmail will block css for security reasons.

Anonymous said...

To target IE7 Only using the inline method is to place "> before the style attribute.

#content {
>width: 120px; #IE7 Only
_width: 130px; #IE6 Only
*width: 165px; #IE6+7
}

Robert Maldon said...

Thanks Arik. Do you know if ">" targets IE8 as well as IE7?

DJ LaBowski said...

@Arik Jones To Target IE 7 use:



Seperates the hacks. more of a best practice... if you want to do IE 7 and later than IE 7 do if lte IE7]

Jason LaBaw

Seattle SEO Bonsai Media Group

Anonymous said...

You just saved my day re: target firefox specific, thanks a bunch. :)