Mathias Bynens

In defense of CSS hacks — introducing “safe CSS hacks”

Published · tagged with CSS, HTML

How do you target Internet Explorer in your CSS? Do you use CSS hacks, conditional stylesheets or something else?

It’s the perfect trollbait. There have been plenty of discussions about this, and I don’t mean to start a new one. Everyone’s entitled to their own opinion, but the thing is that it’s not purely a philosophical matter. I am writing this article because I noticed there’s a lot of misunderstanding on the subject of CSS hacks.

People have been advocating three different approaches: conditional stylesheets, CSS hacks, or conditional classnames. All these techniques have their pros and cons. Let’s take a look.

Conditional stylesheets

Conditional comments make it very easy to specify stylesheets that should only be loaded in Internet Explorer, or even in specific versions of that browser. Non-IE browsers treat conditional comments as any other HTML comment. Here’s an example:

<!--[if lte IE 8]><link rel="stylesheet" href="lte-ie-8.css"><![endif]-->
<!--[if lte IE 7]><link rel="stylesheet" href="lte-ie-7.css"><![endif]-->
<!--[if lte IE 6]><link rel="stylesheet" href="lte-ie-6.css"><![endif]-->

This snippet will cause lte-ie-8.css to be loaded in IE8, IE7, IE6 and even in IE5. (Older IE versions don’t support conditional comments.) In IE7 and older versions, lte-ie-7.css will be loaded as well. In IE6 all three additional stylesheets will be loaded.

If you want to use this technique to style an element differently in specific versions of Internet Explorer, it’d look something like this:

/* Main stylesheet */
.foo { color: black; }

/* lte-ie-8.css, for IE8 and older */
.foo { color: green; }

/* lte-ie-7.css, for IE7 and older */
.foo { color: blue; }

/* lte-ie-6.css, for IE6 and older */
.foo { color: red; }

Pros

  • The conditional comments snippet is valid HTML.
  • Since there’s no need to use CSS hacks, you can even write valid CSS if you want to.

Cons

  • Performance decreases due to the multiple additional HTTP requests, depending on the browser.
  • Conditional comments block downloads in IE unless another (possibly empty) conditional comment is included earlier in the source.
  • The total file size increases, since the conditional comments have to be repeated for every HTML single document, and you’ll have to repeat the selector in every CSS file. More typing work!
  • Maintainability is negatively affected. You now have to maintain four separate stylesheets instead of just one. Whenever you make changes to your main CSS file, you need to remember to change the IE-specific CSS files if necessary.

Conditional classnames

Those not willing to use CSS hacks can always apply conditional classnames to the <html> or <body> element. This approach allows you to write clean and hack-free CSS at the cost of adding hacks conditional comments to your HTML.

<!--[if lt IE 7]><html class="ie6"><![endif]-->
<!--[if IE 7]> <html class="ie7"><![endif]-->
<!--[if IE 8]> <html class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html><!--<![endif]-->

This allows you to keep your browser-specific CSS in the same file:

.foo { color: black; }
.ie8 .foo { color: green; } /* IE8 */
.ie7 .foo { color: blue; } /* IE7 */
.ie6 .foo { color: red; } /* IE6 and IE5 (but who cares, right?) */

Pros

  • The conditional classes snippet is valid HTML. (Prior to HTML5, you would have to add the classes to the <body> element instead.)
  • Since there’s no need to use CSS hacks, you can even write valid CSS if you want to.
  • No additional HTTP requests are being issued to get the IE-specific styles.
  • In this particular case, the conditional comments don’t block downloads.

Cons

  • This technique increases the file size of every HTML document you use it for.
  • The use of the IE-specific classnames automatically increases the specificity of your selectors, which may not be what you want.
  • Since you’ll need the classnames in the selectors, you’ll have to use separate CSS rules for IE-specific styles.
  • The character encoding declaration (e.g. <meta charset="utf-8">) should be placed within the first 1024 bytes of the HTML document. Using this technique, you may cross this limit, especially if you’re adding lots of other attributes to the <html> element (since you’ll have to repeat them inside every conditional comment).
  • Using conditional comments around the opening <html> tag throws IE into compatibility view unless you set the X-UA-Compatible header in a server-side config.
  • Simon Pieters reports that using conditional comments before <meta http-equiv="X-UA-Compatible"> causes IE to ignore the <meta>. So again, you’ll need to set the X-UA-Compatible header in a server-side config.

CSS hacks

Paul Irish maintains a comprehensive list of CSS hacks for various browsers. In reality, you’ll rarely need to specifically target anything but IE. Here’s an overview of the three most popular CSS hacks and which browsers they’re supposed to target:

.foo {
color: black;
color: green\9; /* IE8 and older, but there’s more… */
*color: blue; /* IE7 and older */
_color: red; /* IE6 and older */
}

Note the use of the \9 CSS hack. Web developers noticed it could be used to easily target IE8 and older versions, so that’s what they did. But then there was IE9, and as it turned out, the final IE9 release was still affected by this hack (despite my bug report on the matter). All those CSS declarations that were meant to be for IE8 and earlier versions only, now got interpreted by IE9 as well. Needless to say, stuff broke, since IE9 doesn’t need most of the IE8-specific CSS fixes.

This is the perfect example of an unsafe CSS hack.

Safe CSS hacks

So what constitutes a “safe” CSS hack? What makes me even think there is such a thing?

Let’s face it — CSS hacks are still hacks. There’s no way to accurately predict how future browser versions will parse these rules. But we can make an educated guess — some hacks are less hacky than others. A safe CSS hack is a CSS hack that:

  • works in specific versions of a given web browser;
  • is unlikely to be parsed by all other browsers, including future versions.

Take the _property: value hack, for example. The CSS 2.1 spec says the following:

Keywords and property names beginning with - or _ are reserved for vendor-specific extensions.

A property name is an identifier.

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, two hyphens, or a hyphen followed by a digit.

So who’s to say there will never be a property name starting with an underscore character? To quote the CSS3 spec:

Although [the underscore] is a valid start character, the CSS Working Group believes it will never define any identifiers that start with that character.

Both the _property: value and *property: value hacks (as seen in the above code block) are examples of safe CSS hacks. They were discovered, identified as bugs, and patched in a browser update. Since then, it’s very likely that Microsoft and other browser vendors added checks for these CSS hacks to their layout tests, to make sure no new browser version is shipped with a regression this significant.

If you discover a CSS hack in the latest version of a certain browser, it won’t be a safe hack until an updated version of that browser is released where the parser bug is fixed. For example, some people (myself included) have been looking for an IE9-specific CSS hack. Recently, one was found, but we’ll have to wait at least until the final IE10 release to use it, because IE10 may or may not be shipped with the same CSS parser bug. We can’t risk repeating the history of the \9 hack.

Pros

  • You don’t have to add conditional comments to every single HTML page.
  • No additional HTTP requests are being issued to get the IE-specific styles.
  • The specificity of your CSS selectors is preserved.
  • There’s no need to repeat CSS rules — you can just add extra declarations (with the hacks) to the declaration block.

Cons

  • They’re called CSS hacks for a reason — only use safe CSS hacks.
  • There’s no safe CSS hack for IE8 (yet?).
  • Contrary to conditional comments, most CSS hacks don’t validate. But then again, CSS3 properties and vendor-prefixed properties don’t validate either.

Combining conditional classnames with safe CSS hacks

Safe CSS hacks are preferable to conditional stylesheets or classnames, but what if you have to write IE9-specific styles? By definition, there won’t be a safe CSS hack for IE9 at least until IE10 is released. Also, what about IE8? There is no safe CSS hack (that I know of) that targets IE8 but not IE9. What to do?

In the HTML, we can use a minimal version of the conditional classnames technique, like so:

<!--[if lt IE 9]><html class="lte-ie8"><![endif]-->
<!--[if gt IE 8]><!--><html><!--<![endif]-->

We can then use .lte-ie8 as a styling hook in CSS selectors to target IE8 and older versions. Combined with safe CSS hacks, we can finally target IE8 and older versions without also affecting IE9:

.foo {
color: black;
}

.lte-ie8 .foo {
color: green; /* IE8 and older */
*color: blue; /* IE7 and older */
_color: red; /* IE6 and older */
}

This technique combines all the advantages of safe CSS hacks and conditional classnames, while minimizing the drawbacks.

About me

Hi there! I’m Mathias. I work on Chrome DevTools and the V8 JavaScript engine at Google. HTML, CSS, JavaScript, Unicode, performance, and security get me excited. Follow me on Twitter, Mastodon, and GitHub.

Comments

Nicolas Gallagher wrote on :

Great summary! The last option is quite interesting.

There are a couple of other ways that people might use conditional stylesheets (not significantly different to the example you included, but with slightly different pros/cons).

One is wrapping conditional comments around stylesheets aimed at specific versions of IE to reduce the amount of overriding needed. IE6/7 are pretty similar so they can often get the same stylesheet. Not important (but still possible) to have valid CSS in a stylesheet that only two, stable and well documented browsers will ever see.

<!--[if IE 8]><link rel="stylesheet" href="ie-8.css"><![endif]-->
<!--[if lt IE 8]><link rel="stylesheet" href="ie-6-7.css"><![endif]-->

The other approach (brought to my attention by @bricecarpentier) requires a build script. It wraps every stylesheet in a conditional comment and serves IEs a CSS file that combines the default CSS with the IE-specific CSS. This means you don’t incur an extra HTTP request in old IE.

<!--[if gt IE 7]><!--><link rel="stylesheet" href="style.css"><!--<![endif]-->
<!--[if IE 7]><link rel="stylesheet" href="style.ie-7.css"><![endif]-->
<!--[if IE 6]><link rel="stylesheet" href="style.ie-6.css"><![endif]-->

But both these approaches have the same issues around making maintenance harder.

Thomas Deceuninck wrote on :

Interesting article Mathias! But what to do when you want to set a property specific for one browser? For example:

.foo {
color: red;
}

.ie7 .foo {
color: green;
}

If you use the * prefix for it instead, IE6 will also be affected, right?

Luc De Brouwer wrote on :

I kind of disagree on the cons with the conditional stylesheets solutions.

The performance of the browser due to additional HTTP requests is something you can limit by targeting the specific browser instead of using the lte method. I find that maintainability increases with the different stylesheets because you can keep all CSS “hacks” clearly separated. Of course you shouldn’t need to go apeshit with the amount of needed “hacks”, if that’s the case you did a rubbish job setting up the CSS framework etc. Also the solution Stoyan Stefanov suggested (the empty conditional statement) works like a charm.

However, this is an excellent write-up!

wrote on :

Thomas:

But what to do when you want to set a property specific for one browser?

Can you give me a practical example? 99% of the time if you want to serve specific styles to IE8 to work around a rendering issue, IE7 and IE6 have the same bug, so this cascade is exactly what you want. Most layout bugs that exist in IE8 also exist in 6 & 7; almost all layout bugs in 7 exist in 6. With class names that target versions specifically you end up repeating selectors for IE6, 7 & 8. I guess my CSS code sample is a pretty bad/confusing example :)

Nicolas: Thanks, added. One more reason to use CSS hacks ;)

Morgan Roderick wrote on :

To circumvent the issue of triggering Compatibility View in IE (when did anyone want this, except for activating through specific headers?!), one can use the conditional comments to set class names on the body tag, instead of the html tag.

Nicolas Gallagher wrote on :

Morgan: You could do that. But if you use a CMS or theme that adds lots of classes to the body tag, you can end up with a lot of duplicate HTML and IE6 can’t handle chained classes in CSS selectors (i.e. .ie6.home {})… which might be a problem for you depending on how you write your CSS.

Lennart Schoors wrote on :

Been using hacks for a while now, works like a charm. About the unsafe \9 hack: we serve IE9 users the IE8 fixes – even if that means a less pretty experience. I’m hoping Microsoft will fix this soon in a patch. :)

Rob Flaherty wrote on :

Nice article! I tend to use a single conditional ie.css stylesheet and inside it I use hacks to group specific styles for IE8, IE7, and IE6. It keeps all the hack nastiness sandboxed and reduces the presence of IE-specific code in the HTML to a single line.

I guess I feel better about using hacks when I tuck them away in a separate stylesheet. =)

Morgan Roderick wrote on :

Nicolas: Absolutely, there are always drawbacks when supporting multiple versions of IE, hopefully people understand the repercussions of the choices they make.

Luckily, none of my client projects require me to support IE6 anymore :-)

Zoltan Hawryluk wrote on :

FWIW: I have been using the “conditional comments around the body tag” variation for a while now and it has worked like a charm for me (no technical issues at all). I don’t have to worry about keeping up to date on whether the CSS hacks I have used in all the projects I’ve worked on so far are still safe with a new version of IE (and given all the things I have to worry about IE, having one less thing to worry about is a Really Good Thing™). It is the reason I use it on my recent posts in my blog concerning getting things to work in IE only — it’s really safe.

That said, I think that it is safe to say that any of the solutions above are better than others given the specific situation at hand… it is great that they are listed here in one place, especially with the “safe” strategy for hacks. Excellent post!

Zach Leatherman wrote on :

Using conditional comments around the opening <html> tag throws IE into compatibility view unless you set the X-UA-Compatible header in a server-side config.

Not sure this is accurate. Just because the button shows doesn’t necessarily mean that the page is in compatibility view. If the meta tag was interpreted correctly (or if the HTTP header was sent), the button wouldn’t show at all. But if the button shows and is not depressed, it will still show in the desired Browser Mode (newest).

See the “X-UA-Compatible Flow” section on an article I wrote.

Niels Matthijs wrote on :

Conditional comments make maintenance harder, BUT they also make maintenance easier. If you decide to stop supporting a browser (take IE6), you just remove the link to the IE6-specific CSS and everything is clean again!

Another (although small) pro is that you decrease the filesize of your main CSS a little, because you don’t litter it with CSS hacks for other browsers.

Fabrizio Calderan wrote on :

Cons of technique #2 (conditional classname) could be discussed, IMHO.

This technique increases the file size of every HTML document you use it for.

This is undeniable but we are talking about 50/60 extra bytes that you could easily save elsewhere, maybe by optimizing the JS or the CSS, or with a better image compression, or removing some useless header or removing cookies or… If this is not achievable, the majority of real projects won’t be actually affected with these few extra bytes. I’m not saying extra bytes are good, I’m saying you should evaluate the benefit you reach with this technique as everyone should evaluate carefully where to optimize the code.

The use of the IE-specific classnames automatically increases the specificity of your selectors, which may not be what you want.

…or maybe I may want. This is not necessarily a con. This could be as well a pro, if we consider to code for the standard browser, then specify a stronger rule if a fix is needed, as other people said before.

Since you’ll need the classnames in the selectors, you’ll have to use separate CSS rules for IE-specific styles.

This is absolutely true and this lead to have redundant CSS code. But, again, it depends: if your code doesn’t need to be often fixed on older IE (so you have only a few of specific fixes) this could be a good solution when you will dismiss an IE version. Let’s say you want drop off IE6: you will just remove only the rules starting with .ie6… With mixed hacks you have to delete rules carefully (especially if this is done by someone who doesn’t necessarily know older hacks).

About the latest two cons:

Using conditional comments around the opening <html> tag throws IE into compatibility view unless you set the X-UA-Compatible header in a server-side config.

Simon Pieters reports that using conditional comments before <meta http-equiv="X-UA-Compatible"> causes IE to ignore the <meta>. So again, you’ll need to set the X-UA-Compatible header in a server-side config.

You could use this technique as well in the <body> element. If you rely on this technique on <html> element for the problem described on http://webforscher.wordpress.com/2010/05/20/ie-6-slowing-down-ie-8/ (and you’re using HTML5) I assume you load anyway the innershiv on older IE by a conditional comment soon on the <head> element.

Just some thoughts for discussion. :)

Niels Matthijs wrote on :

…or maybe I may want. This is not necessarily a con. This could be as well a pro, if we consider to code for the standard browser, then specify a stronger rule if a fix is needed, as other people said before.

Normally you don’t want this to happen, as you could have already specified a stronger rule in the original CSS, like so:

.class { color: red; }
.context .class { color: blue; }
.ie6 .class { color: red; }

To each his own, but I believe this is definitely not the way we should be writing CSS. As for readability and ease of understanding someone else’s CSS, this is a true killer.

wrote on :

Fabrizio: Most of your remarks have already been discussed in the comments or the article itself, but still I’d like to respond to this one:

“The use of the IE-specific classnames automatically increases the specificity of your selectors, which may not be what you want.”

…or maybe I may want. This is not necessarily a con. This could be as well a pro, if we consider to code for the standard browser, then specify a stronger rule if a fix is needed, as other people said before.

Sometimes it doesn’t matter, but it’s never a pro. If you want higher specificity you could just extend the selector, or even use !important. The fact that this technique forces the higher specificity only takes away your freedom :)

Jos Hirth wrote on :

Regarding selector specificity with the conditional classnames hack. There actually is a workaround: Just add a dummy class everywhere.

Let’s say we got:

<html class="ie8 any"> or <html class="ie7 any"> or <html class="any"> etc

Then we could use:

.any. foo {...} /* specificity 020 */

…for every browser, and:

.ie8 .foo {...} /* specificity 020 again */

…for targeting IE8.

The obvious downside is some bloat and slightly slower rendering (a few msec perhaps) everywhere.

Ingo Chao wrote on :

I’m by far more afraid of hacks because they are so hard to maintain. Conditional comments or CSS hacks? This does not make much of a difference, since the CSS that comes with them is mostly undocumented by the author and a result of trial and error, copy and paste, or momentary impulse. Therefore, “maintaining” the hack sections of others just adds to the confusion. It is not important how the hacks are delivered, but why. If you cannot explain why your CSS is or is not working, don’t start hacking.

Jens Grochtdreis wrote on :

Thanks for the very detailed summary of this topic. I prefer to handle IE6 and 7 in one extra stylesheet which is linked via conditional comments. Inside this file I use sepcialised hacks to choose only one of both IE if needed. I seldom need hacks for IE8 or 9. If I need one I rely on hacks in the normal CSS.

So it’s a mixture of most of the above.

Robson Sobral wrote on :

I used to avoid hacks until I realized that HTML.className selectors are parsed and tested by all browsers. It is a descendant selector useless that is tested ancestor by ancestor node until the HTML element. Why penalize good browsers because of the bad ones?

Toby wrote on :

For completeness I would mention that server side parsing of the UA string can give you very fine grained information on the browser version. This could be used to generate one or more classes on the HTML element (e.g. .ie .ie8), even down to minor version.

jive wrote on :

I just use conditional comments, anyone on IE really isn't going to really notice another CSS file loaded, plus that extra load is what they get for using IE. :p

But really, as long as the site works and nothing is really broken (nothing on top of something else and the nav links are accessible), just get it to where the site is functional in IE6. That alone will take a lot of the headache away.

Scott van Looy wrote on :

For IE6 specifically, I use:

.general_rule_for_all_browsers_including_ie6_specifics {
/* stuff */
}

Then override it with stuff specifically for other browsers:

* > .general {
/* stuff */
}

The descendant selector is entirely valid but unsupported in IE6. No “hacks” required. As for IE7+, if you write your CSS carefully you don’t require any hacks, I’ve found.

not IE wrote on :

Don’t forget the not IE conditional statement…

<!--[if IE]><p>You are using Internet Explorer.</p><![endif]--> 
<![if !IE]><p>You are not using Internet Explorer.</p><![endif]>

burkanov wrote on :

I'm using a simple JS to place information about rendering engine as a class name to the body. This produces HTML like class="msie vers_7_0" or "mozilla vers_1_9_2" and so on. Then, when I've got to target a specific rendering enginge, I simply point my CSS selector at body.msie.vers_7_0 > [my_selector] and write a normal CSS. Works fine for me.

Rene Kreijveld wrote on :

Great article and great comments. Thanks all. I use a technique where I condionally load separate stylesheets for specific browsers. I develop in PHP and there are some great PHP scripts available that can determine the OS, Browser and Browsers version. Based on these values I can load a specific stylesheet (on top of the default ones) for that browser. The same can be applied for loading Javascripts.

Oliver wrote on :

Whenever possible I try to make it look good in IE9 and IE8. If it works in IE7 ok, if not I don't really care. In IE6 I don't even test anymore.

Pedro wrote on :

burkanov: Thats a good soution, but IE6 will not support multiple classes like your example shows:

body.msie.vers70 So I'd just be careful with that! My favourite solution though.

Rasmus Schultz wrote on :

Here's a thought: use conditional class-names, but use a class-name for "other" browsers not targeted by a browser-specific class-name. That takes care of the specificity problem. Use SCSS and put the "other" browser-class selector around the entire stylesheet. Arguably results in some file-size overhead, but you can roll everything into a single CSS file, which will load once and get cached. I think that's a pretty good trade-off, given the fact that we have to target 4 different versions to get anything to work properly in IE ;-)

Stephan H. Wissel wrote on :

Great article. Solving the browser specific CSS on the client side has the clear advantage that it will work on the dumbest of web servers. However in reality our servers aren't that dumb. So one additional CSS statement like link rel="stylesheet" href="special.css" and a server side browser discovery can sort everything out. depending on how sophisticated your server side will be you could even get away with a single CSS.

wrote on :

Okay, there have been a lot of comments implying that user-agent sniffing (be it server-side or client-side) is a viable alternative to the techniques listed above. Let me get this out of the way: it’s not. Making multiple assumptions based on a single unreliable string is not a very good idea.

The biggest problem with user-agent sniffing is that the UA string is unreliable in itself, since it’s often spoofed by ISPs, proxies, browsers, and users. So even if you write the perfect UA string parser, you can still end up with flawed results. Don’t let your site’s design or functionality depend on it.

Of course, if you would do client-side user-agent sniffing via JavaScript, your site would be broken for visitors with JS disabled.

Please don’t use user-agent sniffing if there’s a perfectly good alternative.

seutje wrote on :

Not too long ago, I was working on this project where I was using Modernizr to detect CSS Multi-columns Layout support, then apply the whole prefixed/non-prefixed she-bang to the csscolumns class, falling back to floats if the detection fails due to it being unsupported or JavaScript being disabled for whatever reason.

This all working nice and dandy, except on certain versions of Safari 5 (5.0.1 and 5.0.2 iirc) on OSX. Here, the test came back positive, clearing of the element I applied column-count to would act as if it worked, but the child elements would just position themselves like regular block-level elements, causing them to bleed into the succeeding element.

I was rather convinced this would be patched out rather quickly, and it did, but obviously I couldn’t rely on this and I was pressured to fix it “right now”. In this case, I could have detected that specific version and made an exception to it, but since I wasn't guaranteed continuous access to the project and time to keep some messed up regex up-to-date, catching only the versions affected by this issue, I was forced to drop CSS Multi-Columns Layout support for all browsers, even the majority where it works fine and live with the fact that my content was displayed in the wrong order…

Anika wrote on :

When I read the title I was assuming you meant rather * html .foo { /* styles for IE6 */ } and *+html .foo { /* styles for IE7 */ }. If something fits the term “safe CSS hack”, I think those are better candidates because they are actually valid CSS.

Alistair Burrowes wrote on :

The use of the IE-specific classnames automatically increases the specificity of your selectors, which may not be what you want.

Can you give an example of where this would be an issue?

Also, I would add a pro to the class name approach that it is the easiest to maintain. (All CSS is in one file. It is self documenting, unlike CSS hacks, which are not obvious and probably necessitate adding comments saying what version the hack is being applied to).

Also, with the class name approach, it is rare that you need to put this on the html tag as opposed to the body tag, so I don't think the issues that this can potentially cause (charset in first 1024 chars) are much of a con.

wrote on :

Alistair:

Can you give an example of where [increased specificity] would be an issue?

Assume you have the following HTML:

<div class="ie"><!-- ← outer div; assume class="ie" is only added in IE -->
<div class="zebra">
<div></div>
<div class="alternate"></div>
<div></div>
<div class="alternate"></div>
</div>
</div>

And this CSS:

.zebra div { background: blue; }
.zebra .alternate { background: lime; }

Let’s say you want to change the blue background to another color in IE. (Of course, I’m using the background property here as an example; in more realistic use cases you would probably want to override different properties.)

.zebra div { background: blue; }
.zebra .alternate { background: lime; }
.ie .zebra div { background: red; }

Simple enough, right? Not really. If you’re not paying close attention, you may not have realised that this will also override the alternate lime background if class="ie" is applied.

In this case, you would have to end up repeating the .alternate selector, or increasing its specificity some other way (by using !important, for example). This is far from ideal.

.zebra div { background: blue; }
.zebra .alternate { background: lime; }
.ie .zebra div { background: red; }
.ie .zebra .alternate { background: lime; }

Here’s a live demo: http://jsfiddle.net/mathias/9gF3E/

Also, with the class name approach, it is rare that you need to put this on the html tag as opposed to the body tag […]

That depends on your coding style, really. If you need to style the html and/or body elements conditionally, you will have to put the class name on the start html tag.

Ali wrote on :

I used if gte ie7 when dealing with compatibility problems with jQuery and CSS. I prefer not to show degraded versions of the CSS, better not to have it at all. More people should start using the newer browsers.

Gav wrote on :

Ali: Couldn’t agree more. If only I could convince the paying clients that the problem lies with outdated, poor browsers that unfortunately so many people are still using…

Steven wrote on :

What happened to the idea of writing code that doesn’t need hacks to work cross browser? It’s 2012 and we still can’t manage to get it right! Nice article though.

Dan Eveland wrote on :

This page is great. I go to it over and over to remind myself how to fix some IE7 issue. Thank you so much for providing this resource!

SJL wrote on :

Thanks Mathias, I have bookmarked this article to refer back to when a bug next pops up in IE!

JoeFlash wrote on :

I was wondering why you were using discrete, single test, IE conditional statements.

<!--[if lte IE 8]><link rel="stylesheet" href="lte-ie-8.css"><![endif]-->
<!--[if lte IE 7]><link rel="stylesheet" href="lte-ie-7.css"><![endif]-->
<!--[if lte IE 6]><link rel="stylesheet" href="lte-ie-6.css"><![endif]-->

Doing it this will cause IE6 to load all three StyleSheets just as you described. However, if you use a more defined statement the problem is avoided.

<!--[if lte IE 8>
<![if gt IE 7]><link rel="stylesheet" href="lte-ie-8.css"><![endif]>
<![if (lte IE 7) & (gt IE 6)]><link rel="stylesheet" href="lte-ie-7.css"><![endif]>
<![if lte IE 6]><link rel="stylesheet" href="lte-ie-6.css"><![endif]>
<[endif]-->

This method should only load the appropriate styling for the target browser version.

Jeff wrote on :

First off, great article. It’s very explicit. I wanted to get your opinion on something. I’m no expert, but a simple conditional for IE8 & below has worked REALLY well for me without having to resort to adding classes to the body or html. Consider the following (VERY SIMPLE) example:

<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="css/style.css">
<!--[if lt IE 9]><link rel="stylesheet" href="css/good-ole-ie.css"><![endif]-->
</head>
<body>

Putting my standard, IE9/Chrome/Fx/Opera/etc browser CSS into the main style.css stylesheet, then IE8 + lower hacks in the conditional good-ole-ie.css stylesheet gives me the results I am looking for. In my example, I put the following CSS into my test:

style.css looks like this:

body { 
background-color: black;
}

good-ole-ie.css looks like this:

body { 
background-color: red;
*background-color: green;
_background-color: blue;
}

Running the above code gives me the desired results. IE6-8 override styles specified in good-ole-ie.css. I can do safe hacks that I know will work in IE6-8 without having to worry about IE9+ misreading them.

Do you see any flaws with this method?

Micah Henning wrote on :

Scott van Looy: Have you checked the performance implications of those CSS selectors? I don’t think it’s a good idea to make all browsers suffer on account of IE’s deficiencies…

Regarding problems in IE 8 and IE 9 that still require hacks, consider the use of a linear gradient as a background for a navigation bar. You’ll find that using IE’s filter property will prevent border-radius from rendering corners in IE 9 (IE 8 doesn’t support border-radius). You may also find that in both IE 8 and IE 9, drop-down menus won’t display when using the filter property, depending on the markup (i.e. <div id="nav" class="filter"><a>Menu Item</a><div id="dropdown"><li><a>Drop-down menu item 1</a></li></div></div>). Therefore, in those cases it may be more appropriate to use a 1px-wide, repeating background image just for IE, or just stick with a plain background color, if allowed. This instance is mostly a problem in cases where altering mark-up is not allowed (like my job); however, I was just providing one of many examples I’ve learned where hacks are still needed for IE7+ browsers.

Leave a comment

Comment on “In defense of CSS hacks — introducing “safe CSS hacks””

Your input will be parsed as Markdown.