Enable CSS pseudo-element selectors in Internet Explorer with IE-CSS3.js

A week ago I was grumbling (again) on Twitter about JavaScript selector engines and enablers for Internet Explorer.

I was looking for a plug-and-play script that enables CSS3 :nth-of-type and other CSS3 selectors in Internet Explorer. John Resig’s Sizzle is, well, incomprehensible to me (at least) and the mighty Dean Edwards’ IE7/8 scripts don’t (yet) support the CSS3 selector types I need.

Then a tweet from Keith Clark (no relation (obviously)).

@Malarkey - Andy, I’ve just finished writing a script that emulates CSS3 selector support in IE if you’re interested. #hardboiled

Interested? Do I live on an orbiting space station?

A few days of testing, recoding (to include support for @import rules), bug fixing and more testing later, Keith fired over his latest version of IE-CSS3.js. A game changer.

ie-css3.js downloads each style sheet on the page and parses it for CSS3 pseudo selectors. If a selector is found it's replaced by CSS class of a similar name. For example: div:nth-child(2) will become div._iecss-nth-child-2. Next, Robert Nyman#8217;s DOMAssistant is used to find the DOM nodes matching the original CSS3 selector and the same CSS class is applied them. Finally, the original stylesheet is replaced with the new version and any elements targeted with CSS3 selectors will be styled.

How to use IE-CSS

To use IE-CSS, include the ie-css3.js script and Robert Nyman’s DOMAssistant in the head of your document. (Your files must run on a web server because of Internet Explorer’s security policy.)

<script src="DOMAssistantCompressed-2.7.4.js" type="text/javascript"></script>
<script src="ie-css3.js" type="text/javascript"></script>

I wrap mine in Conditional Comments to serve it only to Internet Explorer versions 7 and up (I use Universal IE6 CSS for that browser).

<!--[if gte IE 7]>
<script src="DOMAssistantCompressed-2.7.4.js" type="text/javascript"></script>
<script src="ie-css3.js" type="text/javascript"></script>
<![endif]-->

Now, write your HTML as normal. As minimal and free of presentational classes and IDs as you can make it. This is the HTML from my “It’s Hardboiled” authors page.

<section class="authors">
<h1>Hardboiled authors</h1>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
<div class="vcard"><!-- content --></div>
</section>

Followed by your CSS3 selector-based CSS (supported by Firefox 3.5+, Opera 10+ and Webkit).

section.authors .vcard:nth-of-type(1) { /* CSS */ }
section.authors .vcard:nth-of-type(2) { /* CSS */ }
section.authors .vcard:nth-of-type(3) { /* CSS */ }
section.authors .vcard:nth-of-type(4) { /* CSS */ }
section.authors .vcard:nth-of-type(5) { /* CSS */ }
section.authors .vcard:nth-of-type(6) { /* CSS */ }
section.authors .vcard:nth-of-type(7) { /* CSS */ }
section.authors .vcard:nth-of-type(8) { /* CSS */ }
section.authors .vcard:nth-of-type(9) { /* CSS */ }

“It’s Hardboiled” tests


“It’s Hardboiled” authors page in Safari 4


“It’s Hardboiled” authors page in Internet Explorer 8

Now it’s your turn

I hope that you will download IE-CSS and use it on your next project (I'm already trialing it on a client project), test it to its limits and feed back reports so that Keith can make it even better. For that purpose, Keith has set up a Google Group for discussions and feedback.

There have been 41 replies

  1. 1

    John Faulds

    Looks very cool. Will definitely be trying it out on the next site I do.

    (This comment was left on For A Beautiful Web)

    18th Jan 2010
  2. 2

    Richard Tape

    “A game changer.” — A strong statement indeed, Mr. Clarke. However, the way you describe this little gem makes me think that it’s not overstated.  If nothing else, this might, may, perhaps, please god, stop ‘certain people’ from writing comments such as:

    “Yeah, this is great, but until it works in all browsers, I’m not touching it”

    Things like that make me a sad panda. Things like ie-css3.js make me a happy bear!

    18th Jan 2010
  3. 3

    Erwin Heiser

    Nice work, but why not start checking out jQuery for these kinds of fixes?
    http://api.jquery.com/nth-child-selector/

    18th Jan 2010
  4. 4

    Andy Clarke

    Erwin Heiser: Nice work, but why not start checking out jQuery for these kinds of fixes?

    — jQuery was my first port of call, but there seems to be no jQuery to help support :nth-of-type selectors, and they are what I’m demonstrating on that page.

    18th Jan 2010
  5. 5

    Julio Protzek

    jQuerys nth-child selector doesn’t help?
    http://api.jquery.com/nth-child-selector/

    18th Jan 2010
  6. 6

    Tony Wu

    This is brilliant! Definitely gonna have a go at it on my coming up project!

    18th Jan 2010
  7. 7

    Joseph Silvashy

    Andy, jQuery has excellent support for nth-child, and more-so nth-of-type. I’d rather hack a little bit of jQuery than include another library to do something like DOM manipulation.

    Thought?

    18th Jan 2010
  8. 8

    Cesar

    Wicked! will result to this when the need arises.

    18th Jan 2010
  9. 9

    Mathias Bynens

    @Andy,

    jQuery was my first port of call, but there seems to be no jQuery to help support :nth-of-type selectors, and they are what I’m demonstrating on that page.

    Erwin’s comment, to which you were replying, contained a link to http://api.jquery.com/nth-child-selector/, which proves jQuery does support :nth-of-type selectors.

    18th Jan 2010
  10. 10

    Steve Clark

    Jquery is a very heavy library especially if all you are looking at is nth selectors. i think iecss.js is the way forward tiny file size.

    18th Jan 2010
  11. 11

    Mathias Bynens

    Steve Clark: Agreed. But in cases where you’re using jQuery anyway, you might just as well use it to implement these selectors for IE.

    18th Jan 2010
  12. 12

    Ethan

    Andy, The iecss3.js will come in useful. In this case though, I think jquery would’ve done the trick, either with :nth-child (which isn’t exactly the same as nth-of-type, but could’ve worked here) or :eq. But beyond jquery vs. iecss, I think this example might have been best solved by adding ids to your divs. It mucks up the HTML a bit, but:

    1. It saves you the Javascript, which is still necessary for now and is a performance hit.
    2. Using ids actually gives you more separation between content and style, since the author divs could be reordered without needing to change the CSS.
    3. In this case, the structure of the page means that you don’t have to worry about needing to repeat ids, since each author is very clearly unique.
    4. And, since each CSS rule is only styling one item anyway, you aren’t losing efficiency either.

    Just my two cents. Thanks for the article.

    18th Jan 2010
  13. 13

    Tom Davies

    I’ve been playing around with Chris Patterson’s Super selectors, which does a similar-ish thing but via jquery (which will indeed “do” nth-child selectors)

    (http://skulljackpot.com/2009/04/19/super-css-selector-support-with-jquery/)

    Only just started with it so can’t report on performance yet, but it is a little lighter (5.8k min) than the script you mention, once you account for the extra weight of DOMAssistant (JQuery is pretty much a given for me on most sites).

    Tools like these + modernizr (+ less in my case, though it’s not for everyone) make life a heck of a lot more standable while we want n+ years for MS to get with the programme…

    (This comment was left on For A Beautiful Web)

    18th Jan 2010
  14. 14

    Chris

    Well, I really hope it’s way better than Dead Edwards’ IE7.js, because using this got me very, very much trouble and extra work.

    I used IE7.js because you recommend it in your book Transcending CSS. First it looked really nice and I started to use it in all of my projects, private and commercial. Everything went fine, until I used it at a very large project. Unfortunately too late I realized that IE7.js slowed down the HTML templates so much that whenever I opened a page in IE6 there was a delay of a few seconds and even in IE7 there was a noticeable delay. And ther was NO way to stop this. So I had to do it the old fashioned way, kicked IE7.js and adapted the website as good as possible so that it also was usable in IE6.

    And that got me very much extra work and the big problem was that I all had to do that in the last part of the project, where I really had time for nothing. So, I sadly have to say that IE7.js is a big shitload of crap. Dead Edwards himself seems to be too busy or whatever to respond to my emails where I confronted him with my troubles. And so I am very, very disappointed by his script and him too.

    (This comment was left on For A Beautiful Web)

    18th Jan 2010
  15. 15

    Andy Clarke

    Mathias Bynens: Erwin’s comment, to which you were replying, contained a link to http://api.jquery.com/nth-child-selector/, which proves jQuery does support :nth-of-type selectors.

    —  I need :nth-of-type, not :nth-child selectors (different beasts entirely). I also don’t want to write a single $ symbol. Don’t forget, I have no clue about Javascript, not a single line the stuff.

    Ethan: I think this example might have been best solved by adding ids to your divs.

    — You could be right, but that’s not the point. The point is to reduce almost all the unnecessary ID and classes that we use as styling hooks and replace their use with CSS3 selectors.

    18th Jan 2010
  16. 16

    Steve Clark

    @Mathias Bynens yes, If your using Jquery it would make sense to use it.

    Also Keith Clark has written a really lightweight Javascript library called $DOM (http://www.keithclark.co.uk/$dom/). Its not Jquery and does not try to be but for 5k it does scrollers, accordians (Current design trends) and some pretty funky stuff.

    At the end of the day I will use JQuery for most thinks as its Ajax and UI is awesome and simple, but if I dont need these things I will use Keiths ie library or $DOM if I need to do simple scrollers.

    Good work guys.

    18th Jan 2010
  17. 17

    Mathias Bynens

    @Andy:

    I need :nth-of-type, not :nth-child selectors (different beasts entirely).

    Care to explain the difference then? I’m afraid I don’t really get it :(

    Btw, if you don’t wanna use $(), with jQuery, you could just use jQuery(), sayWhat(), or anything you want really.

    18th Jan 2010
  18. 18

    Simon

    Andy, surely as a front-end developer you have to be expected to grasp even the basics of Javascript? I used to be like yourself but the way the industry has changed you can’t just ignore what is now an essential tool in the toolbox.

    18th Jan 2010
  19. 19

    Steve Clark

    This is slowly developing into a debate about Javascript and not reflecting the true nature of the article.

    Regards @Simon comments, if you are a templater who just applies design to html style templates then I would say no you dont need to know about javascript.

    It depends in the way you work. I know guys who design, mock up templates and then pass that on to dev guys who add javascript and server side coding.

    18th Jan 2010
  20. 20

    Keith Clark

    Hi guys,

    If you use jQuery then you’ll need to write your own functions to apply any styles that are defined by unsupported selectors in IE - not all web designers are JavaScript savvy - ie-css3.js parses the style sheet and does it automatically.

    I do understand the point though, if your using JQuery then it’s selector engine is loaded in memory so why download another (ie. DOMAssistant)? Well, as Andy points out, not all selectors are supported in all libraries.

    I was thinking about allowing users to plug their own selector engine into ie-css3.js (allowing you to use jQuery, base2, peppy, sizzle etc.) but this would make the feature support dependent on the library used so I need to give it some more thought. I’m also seriously considering writing an IE8 only version that doesn’t use a 3rd party selector engine but a patched version of querySelectorAll() making it tiny (around 2-3k)

    Ultimately, the aim of this script is to bring IE8’s CSS3 support inline with other browsers of it’s generation so we can start leveraging the power of things like ‘:nth-of-type’ now. Hopefully, when IE9 comes along with (god willing) it’s expected CSS3 support our sites should just work without modification.

    Keith

    18th Jan 2010
  21. 21

    trovster

    How about http://ecsstender.org ? Seems like it was built for exactly this type of use-case.

    (This comment was left on For A Beautiful Web)

    18th Jan 2010
  22. 22

    Jen

    The roles they are a-shiftin’... It seems there was a day where designers could get by without knowing JavaScript, and for those from that era who earned a quality rep, they may stay so. However, those of us who came to it a bit later must learn to understand it.

    Different workflow require different tools. In one, the server-side devs write advanced js, and the client-side designer/dev writes next-to or none. In another, the server-side devs don’t do JavaScript and the front des/dev is exected to handle it. Just last week, a ruby programmer said to me that he didn’t need to learn JavaScript because of the ease of using jquery.

    Now, I tend towards naïveté, but it seems to me that it is helpful if devs know JavaScript, and understand the basics of the constructs. It aids the implementation of js frameworks, it streamlines how css controls might be implemented.

    JavaScript was butt ugly even just eight years ago, but it’s clearer now. It is wise to pick up a copy of [removed] The Good Parts to gain a better grasp on
    this useful tech.

    It looks the :nth-of-type & :nth-child selectors need some clarifying. Who’s gonna get there first? ;)

    18th Jan 2010
  23. 23

    Stephen Hay

    :nth-child() applies style to specific children of an arbitrary parent type. :nth-of-type() applies style to specific instances of a specific type. Thus:

    p:nth-child(2) will style all paragraphs which are the second children of their parent element, and

    p:nth-of-type(2) will style every second instance of ‘p’ in the document tree.

    I think. :)

    18th Jan 2010
  24. 24

    Stephen Hay

    To correct myself:

    p:nth-of-type(2) should style the second instance of ‘p’ in the document tree, not every second instance. That would presumably be p:nth-of-type(2n+1).

    I think. :)

    18th Jan 2010
  25. 25

    Jen

    Stephen: LOL, nicely done. :) Thanks!

    18th Jan 2010
  26. 26

    Nick Bergquist

    @Stephen

    or you could simplify it further with p:nth-of-type(even) to select every second one..

    18th Jan 2010
  27. 27

    Stephen Hay

    @Jen ;)
    @Nick Yes. (even) and (odd) are acceptable shorthand for (an+0) and (an+1) respectively.

    18th Jan 2010
  28. 28

    Stephen Hay

    @Nick: I mean (2n+0) and (2n+1).

    18th Jan 2010
  29. 29

    Nick Bergquist

    @Nick

    Odd… I mean p:nth-of-type(2n+1) is actually p:nth-of-type(odd) as it’s selecting the first incidence then every second.

    18th Jan 2010
  30. 30

    Nick Bergquist

    oOps… I don’t type quick enough.. sorry for any confusion!

    18th Jan 2010
  31. 31

    Stephen Hay

    @Nick I corrected myself (again). See above.

    18th Jan 2010
  32. 32

    Andy Clarke

    Stephen Hay: p:nth-of-type(2) should style the second instance of ‘p’ in the document tree, not every second instance. That would presumably be p:nth-of-type(2n+1).

    — :nth-child is perfect when the content of your document is predictable. For example in list items (that only go inside lists) or table rows/cells that only go inside tables/rows. :nth-of-type is useful for selecting elements anywhere in a document. In my example .vcard:nth-child(x) would not work well because the first vcard is not the first element. But it is the first of its type.

    trovster: How about http://ecsstender.org ? Seems like it was built for exactly this type of use-case.

    — ecsstender is no doubt clever, but even hearing Aaron (its inventor) explain it last year at An Event Apart in Chicago, it far from being a plug-and-play designer tool. It may be perfect for developers who understand how to write Javascript, but it is not what I was looking for.

    Simon: Andy, surely as a front-end developer you have to be expected to grasp even the basics of Javascript? I used to be like yourself but the way the industry has changed you can’t just ignore what is now an essential tool in the toolbox.

    — We all have our skill sets and these cannot be confined to specific labels. As a designer (not a front-end developer), my skills are layout and typography. I also understand HTML and CSS fairly well. Some people think I have a talent for writing and teaching those topics too.

    Javascript in particular and programming in general, requires a thought process that I my brain doesn’t make happen. It doesn’t do numbers either (I’m numerically dyslexic). So I think I’ll stick to what I’m good at and work with people who know far more than me on aspects of projects that don’t suit my skill set.

    18th Jan 2010
  33. 33

    jen Strickland

    “As a designer (not a front-end developer), my skills are layout and typography. I also understand HTML and CSS fairly well. Some people think I have a talent for writing…”

    Ahhh… now this makes sense. The difference is that you provide copy for the sites, where that generally is the responsibility of someone else in the average situation (yes, nothing with Andy Clarke is ever average… we know! ;) ).  In your workflow, you handoff a lot of the development to a trusted individual that is typically expected of designers now.  Your skill at it and your earned reputation make you someone sought after for it.

    It’s starting to make sense, on multiple levels.  I don’t love rewriting someone else’s copy (although that’s exactly what I’ll be doing over the next few weeks, along with design & code) but I do love code, except php & javascript, but I’m not giving up on javascript. Php, though, someone else is welcome to. :-P

    18th Jan 2010
  34. 34

    Aaron Gustafson

    Hey Andy, just so you’re aware, CSS3 selectors (including those you’re using) are supported with the CSS3 Selectors extension (a few tricky ones, like adjacent sibling selectors, aren’t supported yet, but I’m working on the remainder). In fact, I’m using that extension on the eCSStender site right now. You can view the compatibility test in the ZIP file.

    19th Jan 2010
  35. 35

    Diego Perini

    Andy,
    why not a try with NWMatcher, it has support for what you need :nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type , :only-of-type, those pseudos have been available/supported since Dec 2007:

      http://github.com/dperini/nwmatcher/

    it has all what you need in term of CSS3 selectors it is very fast and since version 1.2.0 it allows developers to pass in a callback that will be executed for every visited (and matching) element. The functions to resolve “nth” and “-of-type” pseudos are separated so if you just need them they are just a few hundreds bytes, maybe 1Kbyte with extras ;-)

    You can find a very minimal documentation on GitHub wikis too.

    Best,

    Diego

    20th Jan 2010
  36. 36

    Mathias Bynens

    Now, write your HTML as normal. As minimal and free of presentational classes and IDs as you can make it. This is the HTML from my “It’s Hardboiled” authors page.

    I don’t mean to be nitpicky, but your example code isn’t as “minimal and free of presentational classes and IDs as you can make it”:

    <section class="authors">
    <h1>Hardboiled authors</h1>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    <div class="vcard"><!-- content --></div>
    </section>
    section.authors .vcard:nth-of-type(1) { /* CSS */ }
    section.authors .vcard:nth-of-type(2) { /* CSS */ }
    section.authors .vcard:nth-of-type(3) { /* CSS */ }
    section.authors .vcard:nth-of-type(4) { /* CSS */ }
    section.authors .vcard:nth-of-type(5) { /* CSS */ }
    section.authors .vcard:nth-of-type(6) { /* CSS */ }
    section.authors .vcard:nth-of-type(7) { /* CSS */ }
    section.authors .vcard:nth-of-type(8) { /* CSS */ }
    section.authors .vcard:nth-of-type(9) { /* CSS */ }

    You can omit class=“vcard” from the HTML, and section.authors could just as well be .authors in the CSS (although I think you added that last one for clarity). Here’s what I’d use:

    <section class="authors">
     <h1>Hardboiled authors</h1>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
     <div><!-- content --></div>
    </section>
    .authors div:nth-of-type(1) { /* CSS */ }
    .authors div:nth-of-type(2) { /* CSS */ }
    .authors div:nth-of-type(3) { /* CSS */ }
    .authors div:nth-of-type(4) { /* CSS */ }
    .authors div:nth-of-type(5) { /* CSS */ }
    .authors div:nth-of-type(6) { /* CSS */ }
    .authors div:nth-of-type(7) { /* CSS */ }
    .authors div:nth-of-type(8) { /* CSS */ }
    .authors div:nth-of-type(9) { /* CSS */ }
    20th Jan 2010
  37. 37

    Andy Clarke

    Mathias Bynens: One word, Microformats. Have you heard of them? ;)

    20th Jan 2010
  38. 38

    Mathias Bynens

    @Andy: Ba dum tsss :)

    Sure, I just didn’t realize you would be using the hCard microformat for displaying fake contact info of non-existing detective agencies. I thought you were just using it as a classname. My bad!

    20th Jan 2010
  39. 39

    Derek J. Kinsman

    I have a question not relating to the ie-css3.js thing. Why do you have a whole stack of divs wrapped with a section tag? Why not just:

    <div class=“authors section”>
    <h1>Hardboiled authors</h1>
    <div class=“vcard”><!—content—></div>
    <div class=“vcard”><!—content—></div>
    <div class=“vcard”><!—content—></div>
    <div class=“vcard”><!—content—></div>
    </div>

    I get pushing the new HTML5 elements forward, I just (personally) find Section, Video, & Audio needless and could have been implemented in a different way.

    20th Jan 2010
  40. 40

    Vladimir

    Very good work.
    Thanks

    (This comment was left on For A Beautiful Web)

    21st Jan 2010
  41. 41

    Keith Clark

    @Diego:

    The new version (0.9.3) will automatically detect NWMatcher (among other libraries, including jQuery and MooTools) and use it’s selector engine.

    DOMAssistant still has the best selector support based on my tests. NWMatcher comes out 2nd as it has a problem with a couple of the pseudo selectors when running oth Daniel Glazman’s and the W3C CSS3 selectors test suite. jQuery has limited CSS3 selector support.

    21st Jan 2010
Commenting is not available in this weblog entry.

From the archives

An archive of blog entries since 2004 on subjects including CSS, web standards, accessibility, website design and development.