The WHATWG Blog

Please leave your sense of logic at the door, thanks!

Styling HTML5 markup in IE without script

by Simon Pieters in Browsers, DOM, Elements

The previous post discussed how to enable styling of the new HTML5 elements in IE by using a simple script. However, if the user has scripting disabled, the layout would probably fall apart badly.

So that means if you care about IE users with scripting disabled, you can't use the new elements, right?

Not necessarily.

There are some tricks to work around the broken DOM and limited styling in IE:

  1. Know what the DOM looks like and target other elements than the new elements for styling.
  2. Use the universal selector (*) to target the right element.
  3. Use noscript.

What does this mean?

Target other elements for styling

Consider you have the following markup:

<body>
 <article>
  ...
 </article>
 <nav>
  <ul>
   ...
  </ul>
 </nav>
</body>

Instead of doing this:

* { margin:0; padding:0 }
body { background:silver }
article { border:solid; background:white; margin-left:10em }
nav { position:absolute; top:0; left:0; width:10em }

...do this:

* { margin:0; padding:0 }
html { background:silver }
body { border:solid; background:white; margin-left:10em }
ul { position:absolute; top:0; left:0; width:10em }

Now of course you're going to use other ul elements than the navigation, so how do we get more specific on which element to target? The obvious solution is to set a class or id on the ul element, but there's another solution which might be more convenient in some cases, which brings me to...

Using the universal selector

Depending on the situation, and whether you care about IE6 or not, you can use the universal selector to target the element you want.

Consider you have the following markup:

<body>
 <article>
  <header>
   <h1>...</h1>
   <p>...</p>
  </header>
  ...

...and you want to style the p that is in header, you would do this in the normal case:

article header p { font-weight:bold }

But in IE, the article, header, h1 and p elements are all siblings, so the selector wouldn't match.

So then one would expect this to match, but it doesn't (IE doesn't allow selecting unknown elements using type selectors):

article + header + h1 + p { font-weight:bold }

However, this matches:

body > * + * + h1 + p { font-weight:bold }

Using noscript

The above techniques shouldn't mess up other browsers (or IE when scripting is enabled), however if you prefer (or if something would screw up) you can use a separate style sheet for IE when scripting is disabled by just using the following markup:

<head>
 <!--[if IE]>
  <noscript><link rel="stylesheet" href="ie-noscript.css"></noscript>
 <![endif]-->
 ...

Conclusion

The above techniques might not be very scalable or might well impact maintanence, but the point of this article is to show that it is possible to use the new elements while still supporting IE with scripting disabled.

11 Responses to “Styling HTML5 markup in IE without script”

  1. Thanks for posting these additional approaches; good to keep in mind. If I used the universal selector, however, I would loathe to lose the newfound readability of HTML5’s semantic elements in selectors (as you hinted at). Likewise, if I targeted other elements for styling I’d probably have to add in superfluous markup.

    Another option to serving HTML5 would be to do content-negotiation for MSIE so that all HTML5 block elements get replaced with divs and inline elements with spans, inserting the original HTML5 element name into the class name. For example:

    <article id="foo" class="bar">
    would become:
    <div id="foo" class="bar html5-article">

    And then a stylesheet could have a selector like this:

    article.bar, div.html5-article.bar
    or, of course
    article#foo, div#foo

    At Shepherd Interactive, we’ve used such an approach in several projects and have made available a WordPress plugin that does the element-substitution for IE6 visitors: http://shepherd-interactive.googlecode.com/svn/trunk/wp-plugins/xhtml5-support/xhtml5-support.php

  2. I recently started doing something similar to what Weston suggests on my own blog, except just Firefox 2 and older (so I can continue serving pages as HTML). Wish I’d know about that plug-in though, probably would have saved me hours of work!

    For now I’m using the JS trick for IE, though I might switch that at a later point too.

  3. It hit me that tip #1 applies to Firefox 2 as well, which closes unknown elements when hitting a start tag of a block, so that e.g.

    <article><h1>…</h1>

    …becomes:

    <article></article><h1>…</h1>

  4. Rather than negotiating
    to

    Why not set the article element with a class of article, and substitute a div with a class of article for MSIE, and then style for the class? Makes for simpler CSS.

    But until I’m sure that Google is going to care, I’m leaving HTML5 well alone, just for maintenance reasons. However we are using the html5 element names (section, nav, article, header, footer, video, audio, menu) as our div id’s to facilitate content negotiation for *newer* browsers…

  5. @Weston

    I think the following:

    article.bar, div.bar

    is safer than:

    article.bar, div.html5-article.bar

    because the latter creates selectors with different specificity.