HTML-Node Tagging via Conditional Comments Redux – Same Specificity for Everyone

eye catcher
Can we fix it? No, it's f-ed. :)

In today's episode of Pick your Poison we'll take a brief look at popular options for dealing with Internet Explorer's rendering issues, glitches, and bugs. Basically, it's all about feeding specific versions of IE version specific property/value pairs which happen to yield the desired result(s).

I say "happen", because those pairs are always complete nonsense and they will usually break the layout in horrible ways if a sane browser were to interpret them. Well, we aren't talking about sane browsers today, but we need to make sure that we won't get in their way with these questionable and awkward workarounds.

If you're already familiar with these concepts, you can jump right to "The Small Twist" at the bottom of this article.

Star and Underscore Filters

This is by far the simplest option. There isn't any kind of setup required. There also aren't any additional files, which means no extra requests or template modifications are necessary. It's also pretty pain-free when it comes to maintenance: The IE-X values (if any) are right there!

.foo{
    width:300px;
    *width:310px; /* IE6 and IE7 */
    _width:320px; /* IE6 */
}

The mnemonic I always used for this is very straightforward: * is a wildcard and _ is low. Easy, right?

The problem with this approach is that you can't validate your stylesheet anymore, but with all those vendor prefixes, you're probably using nowadays, it doesn't validate either way.

To tell the truth, you can still validate it, if you add a filtering step prior to the validation step. If you are a big fan of automatic QA/QC, this might be something you should try for yourself.

Selector-based Filters

There is the glitch-exploitation kind like "star html" and "star plus", which only work because some browsers are silly:

/* star html */
* html .foo{
    /* IE6 */
}
/* star plus */
*+html .foo{
    /* IE7 */
}

And there is the feature-detection kind, which targets newer browsers by using more advanced simple selectors, combinators, pseudo classes, or pseudo elements:

html>body .foo{
    /* anything better than IE6 */
}

While these selector-based filters are actually valid CSS, they tend to make maintenance quite a bit harder. Without a comment, the intention is often unclear. E.g. most people will be kinda puzzled if they see a selector starting with :root.

(Spoiler: It allows you to target anything better than IE8.)

Conditional Comments

When it comes to conditional comments you'll usually see this kind of pattern (it's the most popular one):

<link rel="stylesheet" href="everyone.css"/>
<!--[if IE 6]><link rel="stylesheet" href="undead.css"/><![endif]-->

In this case, if IE6 is used, the "undead" stylesheet is loaded as well. It will usually contain a few cherry-picked selectors from the regular stylesheet (and maybe even some completely new selectors) and the required declarations for beating IE6 into submission.

This works pretty well, but from a maintenance point of view it's a real nightmare. Imagine there is an extra stylesheet for IE6, 7, 8, 9, and 10. Are you going to crosscheck them each and every time you change something?

Well, there is no need to answer this rhetorical question. Of course you won't crosscheck everything over and over again. It isn't the path of least resistance. As such, it just isn't actually doable in a team over a longer period of time. Even less so if it's a somewhat bigger project which grows like cancer.

This is were "tagging classes" enter the picture. The setup can look like this for example:

<!--[if IE 6]>  <html class="ie6"><![endif]-->
<!--[if IE 7]>  <html class="ie7"><![endif]-->
<!--[if IE 8]>  <html class="ie8"><![endif]-->
<!--[if IE 9]>  <html class="ie9"><![endif]-->
<!--[if !IE]>--><html>            <!--<![endif]-->

On the CSS side you can now easily target specific IE versions. However, the specificity is also affected:

.foo{ /* specificity: 0.1.0 */
    width:300px; /* every browser */
}
.ie6 .foo, /* specificity: 0.2.0 */
.ie7 .foo{ /* specificity: 0.2.0 */
    width:320px; /* IE6 and IE7 */
}

With a small variation, you can also use "less than" and "greater than" modifiers:

<!--[if IE 6]>     <html class="ie6 lt9 lt8 lt7"><![endif]-->
<!--[if IE 7]>     <html class="ie7 lt9 lt8 gt6"><![endif]-->
<!--[if IE 8]>     <html class="ie8 lt9 gt6 gt7"><![endif]-->
<!--[if IE 9]>     <html class="ie9 gt6 gt7 gt8"><![endif]-->
<!--[if gte IE 10]><html class="gt6 gt7 gt8 gt9"><![endif]-->
<!--[if !IE]>-->   <html>                         <!--<![endif]-->

E.g. that second rule set above can be now written as:

.lt8 .foo{ /* specificity: 0.2.0 */
    width:320px; /* IE <8 */
}

This is a bit nicer, but the specificity of the selectors is still higher than the original selector. This adds some mental overhead since you now also need to keep track of any bizarro world you've created.

The Small Twist

The change of specificity is actually the biggest complaint about this approach, but there is a very simple (yet generally overlooked) solution to this problem: Just add a dummy class!

<!--[if IE 6]>     <html class="ie6 lt9 lt8 lt7 any"><![endif]-->
<!--[if IE 7]>     <html class="ie7 lt9 lt8 any gt6"><![endif]-->
<!--[if IE 8]>     <html class="ie8 lt9 any gt6 gt7"><![endif]-->
<!--[if IE 9]>     <html class="ie9 any gt6 gt7 gt8"><![endif]-->
<!--[if gte IE 10]><html class="any gt6 gt7 gt8 gt9"><![endif]-->
<!--[if !IE]>-->   <html class="any"                ><!--<![endif]-->

With this "any" dummy class added to every incarnation of the html node, we can now add this extra specificity shift to every selector which also exists as override variation:

.any .foo{ /* specificity: 0.2.0 */
    /* any browser */
}
.ie6 .foo{ /* specificity: 0.2.0 */
    /* IE6 */
}

Surprisingly, the overhead in the documents is comparable to the regular include/override solution (with the same number of cases). However, you also send that junk to browsers which don't need it. But at least there isn't that extra request with IE. Overall it's an acceptable compromise, I'd say.

But is it the best one? I'm not really sure. All options kinda suck one way or another. I suggest to go with the one which you think is the least annoying to use. After all, you are the one who has to deal with the downsides of the chosen workaround.

Comments

Interesting

Interesting article, thanks.

Doing a quick search I can see this use of conditional comments proposed by others as well.
Can I ask where you've got inspired from? It won't makes your article less useful or authoritative, I am just curios.

In my articles I usually link most of the sources which brought me to some conclusion so that the reader has more elements to build up his own idea.

Regards,
Antonio http://ao2.it

P.S. Your comment form does not allow to specify a name or a webpage, is that intentional? Maybe to discourage spammers?

re: Interesting

>Can I ask where you've got inspired from?

Using conditional comments to add different classes to the html element is something I came up on my own many many years ago. However, there were many people who had the same idea. I'm not sure who should get credit for that or if there is even anyone who wants to get credit for that.

That I could use some dummy class to get the same (higher) specificity everywhere is something I noticed when I revisited this technique a couple of weeks ago. I also mentioned this in a comment to Mathias Bynens' article about safe CSS Hacks.

HTML5Boilerplate

Check out http://html5boilerplate.com/ and https://github.com/paulirish/html5-boilerplate they are geared towards HTML5 and CSS3 but many approaches apply.
Lots of good info and techniques for dealing with a variety of IE issues, they use modernizr (http://www.modernizr.com/) for browser specific css , except in that case they are using a technique called "feature specific css", which is similar but not quite the same.

re:HTML5Boilerplate

Yes, HTML5Boilerplate does some similar things (if you want). I also highly recommend to check it (and Modernizr) out. :)

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options