Home > CSS > Emulating CSS Child Selectors in IE6

Emulating CSS Child Selectors in IE6


We all hate IE 6. If you don’t hate IE 6, then you just haven’t worked with it enough or you haven’t worked with newer browsers enough to realize what you’re missing. Alas, it still holds such a large market share that it cannot be ignored, so let’s put the whining aside and dig in…

The problem is simple: IE 6 does not support the CSS child selector. It will ignore the following CSS:

table.green > tr > td {
  background-color: green;
  padding: 20px;
}

If you cannot redesign your layout and/or stylesheet to avoid the need for child selectors, then your only option is to emulate the child selector in some way. There are several methods for doing this, and many of them are well documented across the internet, but I will explain them all right here along with their pros and cons. These are the methods I will cover:

  • jQuery
  • CSS Expressions
  • Use More CSS Classes
  • Dean Edwards’ Script
  • CSS Descendant Selector

jQuery

The first possibility is to use jQuery, a very well designed JavaScript library that uses CSS selectors to manipulate the DOM. You can import the jQuery library and then do something like this:

$("table.green > tr > td").css("background-color", "green").css("padding", "20px");

Drawbacks:
  • Requires jQuery or other JavaScript library that supports CSS selectors.
  • Requires the user to have JavaScript enabled.
  • Separates styling logic from CSS.

CSS Expressions

IE supports a CSS construct called a CSS expression that allows you to inject JavaScript into your CSS styles. You can use them to emulate all kinds of CSS selectors and properties that are not supported by IE 6, but they have some major drawbacks that are explained momentarily. This is how you would use CSS expressions to emulate the child selector:

/* CSS selector recognized by everything but IE 6 */
table.green > tr > td {
  background-color: green;
  padding: 20px;
}

/* CSS selector recognized only by IE 6 */
* html table.green tr td {
  background-color: expression(/green/.test(this.parentNode.parentNode.className)? "green" : "transparent");
  padding: expression(/green/.test(this.parentNode.parentNode.className)? "20px" : "0");
}

Drawbacks:
  • CSS expressions are difficult to read and understand.
  • Experts recommend that you avoid CSS expressions due to performance issues.
  • Requires you to know what the “fallback” style should be (in this case, a transparent background and 0 padding).

Use More CSS Classes

This is the brute force approach. You can simply apply a CSS class to every element that you want to style:

CSS:

table.green td.green {
  background-color: green;
  padding: 20px;
}

HTML:

<table class="green">
  <tr>
    <td class="green">A table cell.</td>
  </tr>
</table>

Drawbacks:
  • Tightly couples your CSS with your HTML, which defeats the purpose of decoupling them in the first place.
  • If your CSS developer is a different person than your HTML/content developer, then this can cause a lot more back-and-forth communication.

Dean Edwards’ Script

Dean Edwards, a respected expert in the JavaScript community, has written a script that attempts to turn IE 6 into a standards-compliant browser. The idea is that you write your CSS files as if you only had to deal with standards-compliant browsers like Firefox, then you import Dean’s script and your problems are solved. His script parses your CSS files for certain constructs (such as the CSS child selector) and manipulates the DOM with JavaScript in order to apply the styling. I welcome you to give it a try, but I have had quite a few issues with it and have decided not to use it.

Drawbacks:
  • Requires the user to have JavaScript enabled.
  • Doesn’t always work correctly, especially when it comes to PNG support.

CSS Descendant Selector

The final method for emulating the CSS child selector is to regress to the descendant selector and then “clear” the styling by using another descendant selector:

table.green tr td { /* Specificity: 0,0,1,3 */
  background-color: green;
  padding: 20px;
}

/* Clear the styling of any table cell that is not a direct descendant of table.green */
table.green tr * td { /* Specificity: 0,0,1,3 */
  background-color: transparent;
  padding: 0;
}

Notice that the specificity of the two selectors is the same. This helps to prevent the “clearing” selector from interfering with other CSS selectors.

This solution seems nice and clean, but it has some issues with nested classes. Take the following HTML as an example:

<table class="green">
  <tr>
    <td>
      <table class="green">
        <tr>
          <td>This is a table cell.</td>
        </tr>
      </table>
    </td>
  </tr>
</table>

This is the result (note that I have added a border to help you see the padding):

Not exactly what we were hoping for, right? That’s because the second CSS selector takes precedence over the first one even though they have the same specificity due to their order in the CSS file. Luckily, there is an easy fix for this. We can just switch them around:

/* Clear the styling of any table cell that is not a direct descendant of table.green */
table.green tr * td { /* Specificity: 0,0,1,3 */
  background-color: transparent;
  padding: 0;
}

table.green tr td { /* Specificity: 0,0,1,3 */
  background-color: green;
  padding: 20px;
}

Now let’s take another look:

Much better! Now we have a solution that works in all browsers!

Drawbacks:
  • Requires you to know what the “fallback” style should be (in this case, a transparent background and 0 padding).
  • Requires you to reverse the ordering of your CSS declarations, which is slightly less readable.

Conclusion

I have presented these options to you so you can choose the method that makes the most sense in your project. However, if you need some guidance, then I would suggest the final method (CSS Descendant Selector) because it only has one real drawback which I have always found to be completely manageable.

Good luck!

kick it on DotNetKicks.com

About these ads
Categories: CSS
  1. Sergio de Isidro
    November 23, 2010 at 12:55 pm

    Hello,

    Thank you very much for a very informative article.

    I’d like to point out I do find a drawback to the last method, CSS Descendant Selector. If the nested table does not have a class, the style of the parent table still applies to it, so the “Clear the styling” doesn’t really do anything. The reason is that the second style takes preference over the first one.

    I have been researching on this for some time and I think that the only valid and simple enough solution is applying a class to each TD.

    Cheers!

    • November 23, 2010 at 1:53 pm

      Ah. Yes, you are correct. A nested table without as class name will end up with the same style as the parent. I missed that. I’ll look into this when I get a chance and see if I can come up with a clever solution. I did spend a few minutes thinking about it already, and I’m not sure there is any way around it.

  2. Colin
    September 7, 2012 at 10:07 am

    Hi,

    Great to have come across this article. I have a similar problem but slightly more complicated. Imagine if we had two tables of the same class:

    This is a table cell.

    This is a table cell.

    And I want the first table to display as none, I would use:

    body>table:nth-of-type(1){
    display: none;
    }

    But because of this IE6 bug how can I get around this? I can not change the HTML and can only use CSS.

    Tried

    * html body * table.flindersBody { /* For IE – CL ***/
    display: inline;

    }

    * html body table.flindersBody { /* For IE – CL ***/
    display: none;

    }

    But no use.

    Thanks in advance

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: