1

I have some legacy layouts with nested tables.

I'd like the parent table's <td>s to have borders of one color, while the inner tables have none.

Here:

<html>
  <head>
    <style>
      table tr td{
    border:none;
      }
      table.listTable tr  td
      {
    border:1px solid red;
      }
    </style>
  </head>
  <body>
    <table class="listTable">
      <tr>
    <td>
      left
    </td>

    <td>
      <table style="width:100%;">
        <tr>
          <td>
        1
          </td>
          <td>
        2
          </td>
        </tr>
      </table>
    </td>

    <td>
      right
    </td>
      </tr>
      <tr>
    <td>
      left
    </td>
    <td>
      doubles
    </td>
    <td>
      right
    </td>
      </tr>
    </table>
  </body>
</html>

How do I get the subcells labeled 1 and 2 in the top middle cell to not have the red CSS applied to them by modifying the .listTable css selector?

This seems like what I want:

table.listTable > tr td

But it breaks the selector entirely.

Could someone explain what selector I need, and also why the selector I've tried breaks the layout?

This on jsfiddle: http://jsfiddle.net/nvZbq/

Conrad.Dean
  • 4,341
  • 3
  • 32
  • 41
  • 1
    possible duplicate of [Why doesn't table > tr > td work?](http://stackoverflow.com/questions/5568859/why-doesnt-table-tr-td-work) – BoltClock Nov 04 '11 at 19:47
  • 1
    @BoltClock I would argue it isn't a duplicate. OP didn't know implication of `tr > td` vs. `tr td`. This could be helpful for others. – KP. Nov 04 '11 at 19:55
  • @KP.: You're right — I should have just added a comment saying "this is why your selector is broken" :S – BoltClock Nov 04 '11 at 19:59
  • @BoltClock: I do agree that the problem between these questions is the misunderstanding of getting auto inserted. – Conrad.Dean Nov 05 '11 at 15:22

3 Answers3

4

Look at the generated markup in Firebug or other browser dev tool of your choice. You'll see that <tr>s aren't actually child elements of <table>s. If you don't use a <tbody>, the browser will add one for you.

So here's the selector to use:

table.listTable > tbody > tr > td
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    not all browsers add a tbody, but probably all we care about would – Mark Schultheiss Nov 04 '11 at 20:00
  • I'd guess old builds of IE and Opera. Also, Netscape. – BoltClock Nov 04 '11 at 20:16
  • , and were introduced in IE 4, before the HTML 4.0 specification was adopted. These tags were found useful and were adopted into HTML 4.0. Since Netscape 4 predates IE 4 and HTML 4.0, Netscape 4 and earlier do not recognize these tags. – Mark Schultheiss Nov 04 '11 at 20:31
  • 1
    The fact that tbody gets autoinserted is exactly what was tripping me up. Also I hadn't considered that leaving the child selector between `tr > td` was a bug till you pointed out all my `td`s are still descendants of that one `tr`. Woops. Thanks! – Conrad.Dean Nov 06 '11 at 22:48
  • Note that is optional in XHTML, and will *not* be added to the DOM. Safest option is to just use `table tr` in selectors. – Mark Thomas Nov 07 '11 at 13:15
  • @MarkThomas only if the markup doesn't contain nested tables. – Matt Ball Nov 07 '11 at 14:18
1
table.listTable > tbody > tr > td{
    border:1px solid red;
}

Add the > between tr and td. Remember it signifies a direct child, so table.listTable > tbody > tr > td is describing a table cell (td) that is a direct child of a table row (tr) that is a direct child of a table with the class listTable. The nested table within should not pick up the style now.

Your original style of table.listTable > tr td has two issues. First it signifies ANY td that is nested ANYWHERE below a table row that is a direct child of a table with class listTable. That's why the original style applies the red top border to the sub table. It would do the same for any <td> tag nested below the root table. Second as Matt corrected me below, the browser will insert a <tbody> tag in the table so you need to include it in the CSS selector chain or the direct descendants rules won't work. (Thanks Matt)

Hope this helps.

KP.
  • 13,218
  • 3
  • 40
  • 60
  • @Matt thanks, good catch. Updated. Original issue described still applies, plus what you pointed out. – KP. Nov 04 '11 at 19:53
0

The issue is the specificity of the selector with the borders. It is MORE specific than the one without.

There are several ways to accomplish this.

One way would be to ADD specificity to the innner table selector:

table.listTable table tr td

EDIT NOTE: the "child" vs "direct child" comes into play with the '>' in your selector when some browsers add the tbody, and some not.

table.listTable tr  td       {     border:1px solid red;       } 
table.listTable table tr td{     border:none;       } 

example: http://jsbin.com/oyihop/edit#javascript,html,live

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
  • IMO that gets messy, and would be better to directly target the element you want, rather than targeting all tds first and then 'erasing' styles on nested elements through a second style definition. That's just me though.. – KP. Nov 04 '11 at 19:50
  • 2
    "child" and "direct child" mean the same thing. – BoltClock Nov 04 '11 at 19:50
  • @BoldClock well table>td is not exactly the same as table td. Perhaps my terminology is not quite clear but "direct child" in my reference would NOT mean grandchild – Mark Schultheiss Nov 04 '11 at 19:58
  • @KP yes, but the idea here is to demonstrate the point quite clearly. – Mark Schultheiss Nov 04 '11 at 19:59
  • @MarkSchultheiss: I think the spec and other sites use the word 'descendant' to refer to child, grandchild, and any other elements further down the DOM tree. – Conrad.Dean Nov 06 '11 at 22:44