CSS Alternate Rows - some rows hidden
Asked Answered
I

6

24

I'm trying to style a table so that each row is a different colour (odd/even). I have the following CSS:

#woo tr:nth-child(even) td {
    background-color: #f0f9ff;
}

#woo tr:nth-child(odd) td {
    background-color: white;
}

However, some of my rows can be hidden and I'd still like the rows to alternate. How can I adjust the above so it gives the appearance of alternate rows, even if the rows that are next to each others aren't necessarily odd and even?

Inlet answered 2/6, 2011 at 21:26 Comment(2)
I hide the rows with "display: none".Inlet
just a quick though: is really necessary to have thousand of rows? You cannot use pagination ?Fleabag
D
25

If you are using jQuery, you can employ one of its functions, for example .filter(), to choose only the elements that are visible. But the key here is a CSS selector :visible.

For example (see jsfiddle):

jQuery('tr:visible:odd').css({'background-color': 'red'});
jQuery('tr:visible:even').css({'background-color': 'yellow'});
Deranged answered 2/6, 2011 at 21:29 Comment(2)
I actually tried this, but as my table grew in size, as its always being added to, this seemed to bring firefox to a standstill, hence why i was looking for a purely CSS 'fix' to see if i could alleviate the JS burden on my page.Inlet
As I said, the key here is CSS selector, but it is probably not working in deprecated browsers, like older IE versions (please test whether it works in browsers you want to support). If pure CSS-only solution does not satisfy you, only one that is left is adding specific classes by JS (probably altering my solution, though).Deranged
W
5

Since the "missing stripe phenomenon" only occurs if an odd number of rows is hidden, you might get away with adding a single invisible padding row wherever an odd number of rows is hidden.

Row 1
Row 2
Row 3 (hidden)
Padding (hidden)
Row 4
Row 5

If this actually is a good solution highly depends on your current code, e.g. how you create the table and how rows are hidden.

But if your tables are huge and large chunks of consecutive rows are hidden, this would perform much better than a Javascript/jQuery solution.

Wrestling answered 10/10, 2013 at 10:2 Comment(1)
Simply genius!!Undemonstrative
E
3

I solved this issue using a background image for the table that consisted of the two alternate colors. This makes for not-quite-a-full-CSS solution as it involves creating an image, but it should scale very well for tables with thousands of entries.

The background-image in the base64 encoding below is a 1x50 image with the top 25 pixels as one color and the bottom 25 pixels as the alternate color.

table {
  border-collapse: collapse;
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAIAAAASmSbdAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wQbATAssXhCIwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAYSURBVAjXY/j8/joTAwMDTfGXDzdpbQcATuQF2Ze0VigAAAAASUVORK5CYII=);
}
  
td {
   padding: 2px 4px;
   height: 21px;
}
<table>
    <tbody>
        <tr style="display: table-row;">
            <td>ANIMAL!!</td>
        </tr>
        <tr style="display: table-row;">
            <td>Beaker</td>
        </tr>
        <tr style="display: none;">
            <td>Bunsen Honeydew, Ph.D.</td>
        </tr>
        <tr style="display: table-row;">
            <td>Camilla the Chicken</td>
        </tr>
        <tr style="display: table-row;">
            <td>Dr. Julius Strangepork</td>
        </tr>
        <tr style="display: none;">
            <td>Dr. Teeth</td>
        </tr>
        <tr style="display: none;">
            <td>Floyd Pepper</td>
        </tr>
        <tr style="display: none;">
            <td>Gonzo</td>
        </tr>
        <tr style="display: table-row;">
            <td>Janice</td>
        </tr>
        <tr style="display: none;">
            <td>Miss Piggy</td>
        </tr>
        <tr style="display: none;">
            <td>Rizzo</td>
        </tr>
        <tr style="display: none;">
            <td>Robin the Frog</td>
        </tr>
        <tr style="display: table-row;">
            <td>Sam the Eagle</td>
        </tr>
        <tr style="display: table-row;">
            <td>Statler</td>
        </tr>
        <tr style="display: none;">
            <td>The Swedish Chef</td>
        </tr>
        <tr style="display: table-row;">
            <td>Waldorf</td>
        </tr>
        <tr style="display: none;">
            <td>Zoot</td>
        </tr>
    </tbody>
</table>
Ecstatics answered 27/4, 2015 at 2:7 Comment(0)
C
2

I realize this is super late, but I ran into this same problem today and came up with a pure CSS solution using an nth-child formula. I don't know if it fits your exact scenario, but if every other row is hidden but you still need the visible rows to be alternating colors, this works great. The CSS selector looks like this:

tr:nth-child(4n - 1) { background-color: grey; }

Here is a fiddle showing it in action.

This makes every other visible row grey. For more information on how these formulas work, this is a great tutorial.

Chilli answered 6/3, 2015 at 0:52 Comment(3)
This answer is the best in my case. Some of the rows can become visible, but I do not want them to be included in background colour change, so this works better than the jquery : visible solution for me. Thanks!Salesman
This only works if every 2nd row is hidden, but if you use a filter that causes random rows to be hidden, then this code doesn't work anymore.Rumal
@Rumal - that is why I stated if every other row is hidden, and suggested it might not fit the exact scenario. Not sure a down-vote is deserved but ¯_(ツ)_/¯Chilli
S
2

This question might be old, but when looking for a solution to that problem I came here and inspired by Jeff Seifert's answer I used a repeating-linear gradient background image to have a purely css based solution:

tbody {
    background-image: repeating-linear-gradient(grey 0 2em, white 2em 4em);
}
tr {
    height: 2em;
}

The only thing downside is, that you will have to specify a height for the table row (and put the same value in the gradient definition).

EDIT: This only works if all rows have the same height. Sadly max-height does not work for table rows. I have two half-baked solutions for that:

  1. Prevent text from wrapping by applying tr{white-space: nowrap;} - Care still has to be taken for non-text elements, overflow could also become an issue

  2. Wrap the <tr> content with another element like a <div> and apply div{max-height:2em;} - This requires changes in the HTML and also needs treatment of overflow

Steamheated answered 18/7, 2020 at 11:24 Comment(0)
L
1

This is a hard problem, I just spent a while playing with CSS2 and 3 selectors, and I'm not sure we're there yet. Something like this should be possible, but doesn't work:

tr td {background-color:white;}
tr td:not([style="display:none"]):nth-of-type(even) {
    background-color:#f0f9ff;
}

<tr><td>1</td></tr>
<tr><td style="display:none">2</td></tr>
<tr><td>3</td></tr>

Seems you're stuck with jQuery's :visible extension (not native CSS), but if it's running slow, definitely paginate the rows as @Ionut says.

Lothar answered 4/6, 2011 at 12:8 Comment(1)
Nice idea, but it doesn't work because nth-of-type doesn't consider any other selectors, but only the element type. (In XML-speak it would be the node name) Perhaps one day we'll have a nth-of-selector-match selector :)Wrestling

© 2022 - 2024 — McMap. All rights reserved.