22

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?

Ry-
  • 199,309
  • 51
  • 404
  • 420
xyz
  • 223
  • 2
  • 4
  • 1
    I can't see how to avoid jQuery unless you're able to keep your tables to have one tbody only. – Scott Christopherson May 30 '10 at 23:43
  • Give each row a class 'ODD' or 'EVEN'. Then use CSS to color the classes, not the table cells. –  Jan 21 '14 at 05:22
  • Related: [Select nth-child across multiple parents](http://stackoverflow.com/questions/17652543/select-nth-child-across-multiple-parents) – user Jan 22 '14 at 15:35

6 Answers6

11

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.

Community
  • 1
  • 1
Nick Craver
  • 594,859
  • 130
  • 1,270
  • 1,139
  • That doesn't solve the question he's trying to have answered. This is just a jQuery version of his problem. – Scott Christopherson May 30 '10 at 23:50
  • @Scott - It does solve the problem, did you look at the demo? You have to remove and re-apply the class when visibility changes, just like the javascript solution...if you have a simpler non-javascript solution I'd love to see it, but I don't see how that's possible. – Nick Craver May 30 '10 at 23:50
  • Ah this is correct, I completely misunderstood. I'm trying to change my vote but it's not allowing me unless an edit is made. – Scott Christopherson May 30 '10 at 23:57
  • @Scott - Updated - added additional handling or visibility as per the question. – Nick Craver May 31 '10 at 00:01
  • 1
    Ah nice, I wouldn't have considered visibility. – Scott Christopherson May 31 '10 at 00:04
  • Well, I suppose I don't have a choice. :) Thank you. – xyz May 31 '10 at 00:05
  • Question is tbody show/hide. When i removed style from tr and added display none in second tbody. "Like this" demo not worked well. – Shyam Jan 16 '14 at 04:52
  • @shyamji1983 there are multiple ways to hide a tbody. Also it *does* work fine, you're just trying a demo with an ancient version of jQuery. Notice it works fine with the current version: http://jsfiddle.net/FmLKq/5/ – Nick Craver Jan 16 '14 at 10:59
  • You can actually use CSS to color the class. I did this in my HTML5/CSS class. We did not use any other languages. –  Jan 21 '14 at 05:24
  • I agree on `no pure css solution` part and upvote this simple yet nice answer – FreshPro Jan 21 '14 at 15:32
7

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!

Ry-
  • 199,309
  • 51
  • 404
  • 420
  • That selector matches `tbody` with an even number of children - I'm not sure that selector alone would be enough. I'm thinking of something like `tr:nth-match(even of #table > tbody > tr)` instead, which is probably equivalent to `$('#table > tbody > tr:odd')`, but Selectors 4 might not allow `!` or combinators in `:nth-match()` to be used in CSS, which would mean you'd still have to fall back to JS either way. – BoltClock Jan 16 '14 at 04:22
  • (I’m trying to think of ways to abuse wrapping and Roman-numeral-style CSS counters to have a *CSS2-compatible thing* for this, but no luck so far.) – Ry- Jan 16 '14 at 05:12
  • @minitech The problem is turning the counter into a number that can use the modular operator http://codepen.io/Zeaklous/pen/djtBz – Zach Saucier Jan 16 '14 at 06:27
  • @BoltClock `nth-match` will not work, I examined that. See my answer. – Tomas Jan 18 '14 at 08:13
  • Clever and upvoted, but giving the bounty to the "not possible" answer. – Jeremy Kauffman Jan 22 '14 at 14:45
6

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.
Community
  • 1
  • 1
Tomas
  • 52,167
  • 46
  • 207
  • 345
1

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>
1

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.

Community
  • 1
  • 1
vals
  • 54,758
  • 10
  • 75
  • 124
  • *“Then I can force this pseudo element to extend to all the tr.”* How? – Ry- Jan 21 '14 at 14:36
  • I suppose `transform: scale(something big);` and `overflow: hidden;` would probably do the trick… – Ry- Jan 21 '14 at 14:37
  • Providing a simple example code how this would work for the table would make this answer much more useful :) – Tomas Jan 22 '14 at 11:56
0

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';
bobince
  • 498,320
  • 101
  • 621
  • 807
  • I forgot to mention, I don't care about compatibility. I'm only going to support browsers that support CSS3. Writing a script, especially using jQuery, is not much of a problem. But I really wanted to avoid it, as the table is dynamic and I would have to reapply a lot. – xyz May 30 '10 at 23:48