Vladimir
Vladimir

Reputation: 369

CSS siblings groups. Trick required

Ok, so I got this:

<tr class="group expanded"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>
<tr class="group expanded"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>
<tr class="group expanded"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>
<tr class="row"> ... </tr>

when someone clicks the group, the class changed by jQuery from expanded to collapsed. When expanded the rows below this group should be visible, when collapsed - hidden. I want to do this with CSS only. The following is not working:

tr.expanded ~ tr.row { display:table-row; }
tr.collapsed ~ tr.row { display:none; }

because if we got a sequence expanded-collapsed-expanded, the third group rows (and all others) would be hidden even if the group is expanded due to css priority (declaration of collapsed comes after expanded). What should I do? I'm sure there should be a trick. :)

The number of groups and the rows after it differs.

Please do not suggest me to make a hierarchy of the elements to be rows be contained by the group, I want to solve this like it is.

Thank you in advance!

Upvotes: 2

Views: 186

Answers (3)

TimSPQR
TimSPQR

Reputation: 2984

Can you live with a kludge like this? FIDDLE.

It's a checkbox hack (attributed as a comment in the js section).

If you don't insist on having the clickable row be a series of td's, might be useful.

NB: I've been playing a bit and you can actually put a small table within a <label> tag and it seems to work OK - another FIDDLE.

CSS

table td {
    width: 54px;
    border: 1px solid gray;
    text-align: center;
}
input#row1[type=checkbox]:checked ~ .table1 {
   display: block;
}
input#row2[type=checkbox]:checked ~ .table2 {
   display: block;
}
input[type=checkbox] {
   position: absolute;
   top: -9999px;
   left: -9999px;
}
#upperlabel { 
  width: 300px;
  height: 20px;
  background-color: blue;
  color: white;
  display: block;
  line-height: 20px;
  text-align: center;
}
#middlelabel { 
  width: 300px;
  height: 20px;
  background-color: red;
  color: white;
  display: block;
  line-height: 20px;
  text-align: center;
}
.table1 {
   display: none;
}
.table2 {
   display: none;
}

Upvotes: 0

Bram Vanroy
Bram Vanroy

Reputation: 28505

I had hoped the general sibling selector would prove a solution in combination with :not(). Something like this.

tr.expanded + tr:not(.collapsed ~ .row) {
    display: table-row;
}
tr.collapsed + tr:not(.expanded ~ .row) {
    display: none;
} 

However, :not only accepts simple selectors, which the general sibling selector is not.

As BoltClock proposes, nextUntil should solve your problems fine. Especially if you are already working with jQuery, this shouldn't prove to be a problem. Here is a test case.

$(".group").click(function () {
    $(this).toggleClass("expanded").toggleClass("collapsed").nextUntil(".group","tr.row").toggle();
});

(I kept the alternating classes, so you can style the headers (.group) accordingly, if you want.)

Upvotes: 0

BoltClock
BoltClock

Reputation: 724202

There is no way using only CSS to select only a limited set of following siblings until the next occurrence of some other sibling. See my answer to this similar question.

If you cannot modify your HTML for whatever reason, your only option is jQuery, which provides a .nextUntil() method for this specific purpose.

Upvotes: 3

Related Questions