Pure CSS3 solution to stripe table with multiple <tbody> elements?

I've got a table with multiple <tbody> elements. At a given time, only one <tbody> is displayed, or all of them are displayed.

I currently use this CSS3 code to stripe the table:

table tr:nth-child(even) {
  background: #efefef;
}

When a single <tbody> element is shown, everything is (obviously) fine, but when multiple <tbody> elements are shown the CSS rules apply to each one separately, and each <tbody> has its own “stripes system”. Together the stripes may or may not look consistent, depending on the number of rows.

<tbody>
  <tr> [ODD]
  <tr> [EVEN]
  <tr> [ODD]
</tbody>
<tbody>
  <tr> [ODD]
  <tr> [EVEN]
</tbody>
…

Would I absolutely have to use JavaScript (… jQuery) to fix this? Or is there a pure CSS solution?

Answers


If you're using jQuery then use the :even selector, (edited: to handle visibility) like this:

$("table tr:visible:even").addClass("even");​

And a class like this:

.even { background: #efefef; }

Again, that's if you're using jQuery already, if you're not go with a pure javascript solution (including any library for just this is overkill) like bobince posted. Either way I don't see a pure CSS solution here...it's definitely a valid case, but not something that comes up often enough to make it spec-worthy.


If you have rows that are all the same height, you can cheat with a gradient, e.g.:

#table {
    background-image: repeating-linear-gradient(pink 0, pink 1.6em, yellow 1.6em, yellow 3.2em);
    background-repeat: no-repeat;

    /* To account for headers; adjust size to account for footers.
     * You can also use a second (or third) gradient for both.
     */
    background-position: 0 1.4em;
}

If you can guarantee that all <tbody> elements have an even number of rows, you can also make use of that (even if the last one is hidden), but otherwise, you’re out of luck. Selectors Level 4 might have something to say about it, though, with something along the lines of

#table > !tbody > tr:last-child:nth-child(even)

making up for the class.

Demo!


After intensive research, I can state that

There is no pure CSS3 (not even CSS4) solution to match even/odd rows accross multiple parents.

All solutions you would think of are impossible:

  1. Use the :nth-child pseudo-class.

    Verdict: This will only work within a single parent.

  2. Somehow involve the tbody tags with odd number of rows (color switchers) by counting their children and distinguishing those with odd rows in a similar way nth-child(odd) works.

    Verdict: In CSS it is not possible to count children, see this question. Beware of the confusing accepted answer - this is in fact counting siblings, not children

  3. Try to match only some tbodys based on some children CSS rule, and thus being able to identify tbodys with odd number of children.

    Verdict: In CSS it is not possible to match elements according to their children:

  4. CSS4 introduces a new selector :nth-match, which sounds promising as it doesn't contain the word "child" in it. So you would wonder if this would work:

:nth-match(even of tr) { background-color: #ccc; }
:nth-match(odd of tr) { background-color: #fff; }

Verdict: It doesn't work. If you look at the description, you see it will do exactly the same thing you observe:

The :nth-match(An+B of <selector>)pseudo-class notation represents an element that has An+B-1 siblings that match the given selector list before it in the document tree.

The problematic is the word siblings which mean it will only count within each tbody tag, as the :nth-child selectors do.

Conclusion

There is no pure CSS (neither CSS3 nor CSS4) solution. You will have to refrain to either:

  • javascript, e.g. the great jQuery solution mentioned by Nick Craver;
  • minitech's background trick, but its use is limited to equal-height rows;
  • changes in the HTML generation code.

If Use JQuery then Use this Code :

//style for even CSS Class
<style>.even { background: #efefef; } </style>

Add class to every second row of tables for styling purposes

 <script>
   $('tbody').parents('.table-container').find('tr:even').addClass( 'even' );
 </script>

HTML Code

<div class="table-container">
    <table>
        <tbody>
          <tr> [ODD]
          <tr> [EVEN]
          <tr> [ODD]
        </tbody>
        <tbody>
          <tr> [ODD]
          <tr> [EVEN]
        </tbody>
    </table>
</div>

A solution that for now won't work in any browser (as far as I know) would be using counters (on the tr) and then use that from w3c counter styles level 3:

w3c doc

3.1.1. Cycling Symbols: the ‘cyclic’ system

The ‘cyclic’ counter system cycles repeatedly through its provided symbols, looping back to the beginning when it reaches the end of the list. It can be used for simple bullets (just provide a single counter symbol), or for cycling through multiple symbols. The first counter symbol is used as the representation of the value 1, the second counter symbol (if it exists) is used as the representation of the value 2, etc.

If the system is ‘cyclic’, the ‘symbols’ descriptor must contain at least one counter symbol, or else the ‘@counter-style’ rule is invalid. This system is defined over all counter values.

A "triangle bullet" counter style can be defined as:

@counter-style triangle { system: cyclic; symbols: ‣; suffix: ''; }

It will then produce lists that look like:

‣ One ‣ Two ‣ Three If there are N counter symbols and a representation is being constructed for the integer value, the representation is the counter symbol at index ( (value-1) mod N) of the list of counter symbols (0-indexed).

If I set this rule with 2 symbols, one a filled square an the other an empty square, I get a pseudo element that is alternating between a color and transparency.

Then I can force this pseudo element to extend to all the tr.


Yeah, I think you would need script, as there is no nth-grandchild selector that would work relative to the <table>. You'd need script to make it work in older browsers anyway, so probably not a big deal.

var table= document.getElementById('sometable');
for (var i= table.rows.length; i-->0;)
    table.rows[i].className= i%2===0? 'stripe-even' : 'stripe-odd';

Need Your Help

Preventing HttpClient 4 from following redirect

android google-app-engine apache-commons

I'm connecting to my AppEngine application using the Apache HttpComponents library. In order to authenticate my users, I need to pass an authentication token along to the application's login addre...

The R console is in my native language, how can I set R to English?

windows r localization settings rstudio

I am using R on Windows 7. Apparently R somehow found evidence that I speak languages besides English, and stubbornly insists on giving output in the console in my own language. For a variety of re...