Better conditional classnames for hack-free CSS

Applying conditional classnames to the html element is a popular way to help target specific versions of IE with CSS fixes. It was first described by Paul Irish and is a feature of the HTML5 Boilerplate. Despite all its benefits, there are still a couple of niggling issues. Here are some hacky variants that side-step those issues.

An article by Paul Irish, Conditional stylesheets vs CSS hacks? Answer: Neither!, first proposed that conditional comments be used on the openinghtml tag to help target legacy versions of IE with CSS fixes. Since its inclusion in the HTML5 Boilerplate project, contributors have further refined the technique.

However, there are still some niggling issues with the “classic” conditional comments approach, which Mathias Bynens summarized in a recent article on safe CSS hacks.

  1. The Compatibility View icon is displayed in IE8 and IE9 if you are not setting the X-UA-Compatible header in a server config.
  2. The character encoding declaration might not be fully contained within the first 1024 bytes of the HTML document if you need to include several attributes on each version of the opening html tag (e.g. Facebook xmlns junk)

You can read more about the related discussions in issue #286 and issue #378 at the HTML5 Boilerplate GitHub repository.

The “bubble up” conditional comments method

Although not necessarily recommended, it looks like both of these issues can be avoided with a bit of trickery. You can create an uncommented opening html tag upon which any shared attributes (so no class attribute) can be set. The conditional classes are then assigned in a second html tag that appears after the <meta http-equiv="X-UA-Compatible"> tag in the document. The classes will “bubble up” to the uncommented tag.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="X-UA-Compatible"
          content="IE=edge,chrome=1">
    <meta charset="utf-8">
    <!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
    <!--[if IE 7]><html class="no-js ie7"><![endif]-->
    <!--[if IE 8]><html class="no-js ie8"><![endif]-->
    <!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->

    <title>Document</title>
  </head>
  <body>
  </body>
</html>

Fork the Gist

The result is that IE8 and IE9 won’t ignore the <meta http-equiv="X-UA-Compatible"> tag, the Compatibility View icon will not be displayed, and the amount of repeated code is reduced. Obviously, including a secondhtml tag in the head isn’t pretty or valid HTML.

If you’re using a server-side config to set the X-UA-Compatible header (instead of the meta tag), then you can still benefit from the DRYer nature of using two opening html tags and it isn’t necessary to include the conditional comments in the head of the document. However, you might still want to do so if you risk not containing the character encoding declaration within the first 1024 bytes of the document.

<!DOCTYPE html>
<html lang="en">
<!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
<!--[if IE 7]><html class="no-js ie7"><![endif]-->
<!--[if IE 8]><html class="no-js ie8"><![endif]-->
<!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
  <head>
    <meta charset="utf-8">
    <title>Document</title>
  </head>
  <body>
  </body>
</html>

Fork the Gist

The “preemptive” conditional comments method

Another method to prevent the Compatibility View icon from showing was found by Julien Wajsberg. It relies on including a conditional comment before the DOCTYPE. Doing this seems to help IE recognise the <meta http-equiv="X-UA-Compatible"> tag. This method isn’t as DRY and doesn’t have the character encoding declaration as high up in the document, but it also doesn’t use 2 opening html elements.

<!--[if IE]><![endif]-->
<!DOCTYPE html>
<!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
<!--[if IE 7]><html class="no-js ie7"><![endif]-->
<!--[if IE 8]><html class="no-js ie8"><![endif]-->
<!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta charset="utf-8">
    <title>Document</title>
  </head>
  <body>
  </body>
</html>

Fork the Gist

While it’s interesting to explore these possibilities, the “classic” method is still generally the cleanest. It doesn’t create invalid HTML, doesn’t risk throwing IE into quirks mode, and you won’t have a problem with the Compatibility View icon if you use a server-side config.

If you find any other approaches, or problems with those posted here, please leave a comment but also consider adding what you’ve found to the relevant issues in the HTML5 Boilerplate GitHub repository.

Thanks to Paul Irish for feedback and suggestions.

Leave a comment