Selecting child elements in groups, and treating each group differently

Problem

Say I have multiple list items in a <ul>, and there are groups of items than contain the .aggregated class. Like this:

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
    <li></li>
    <li></li>
    <li></li>
    <li class="aggregated"></li>
    <li class="aggregated"></li>
</ul>

I need to be able to style each of those groups of <li> elements differently, basically giving each group a different background color. So, the first group of <li class="aggregated"> would have a blue background, and the second group a yellow background, etc. I don't want to rely on JS and don't want to add arbitrary class names or IDs. I'd like to use the code that's already in place.

Possible? If so, how?

Problem courtesy of: Brandon Durham

Solution

Okay, this is possible. But it's insanely fragile, and relies on there being predictable classes, also it requires a modern browser:

/* presentational stuff */

li ~ li.aggregated,
li.aggregated ~ li.aggregated {
    background-color: #f90;
}

li.aggregated ~ li:not(.aggregated) ~ li.aggregated {
    background-color: #ffa;
}

li.aggregated ~ li:not(.aggregated) ~ li.aggregated ~ li:not(.aggregated) ~ li.aggregated {
    background-color: #cfc;
}​

JS Fiddle demo.

Solution courtesy of: David Thomas

Discussion

If you look at any item that has the class where the element before it does not, you can define group numbers and increment them accordingly.

var groupNum = 1;
// Get all <li>
$("ul li").each( function() {
    var element = $(this);
    if( element.hasClass("aggregated") ) {
        if( !element.prev().hasClass("aggregated") ) {
            // Prev element was not in this group. increment the group number
            groupNum++;
        }
        switch( groupNum ) {
            case 1:
                // group #1 styles
                // element.css( "background-color", "#FFF" );
                break;
            case 2:
                // group #2 styles
                // element.css( "background-color", "#00F" );
                break;
        }
    }
} );
Discussion courtesy of: Ben Roux

Instead of adding custom class to each list item of the group you can group the items with a div, for example:

<ul>
    <li></li>
    <li></li>
    <li></li>
    <div class="group">
      <li></li>
      <li></li>
      <li></li>
    </div>
</ul>

Then you can select the groups you are interested in using nth-of-type selector, for example:

ul > .group:nth-of-type(1) > li
{
    background-color:red;
}

nth-of-type selector allows you to select items by number, keyword, or formula.


Example jsFiddle.

Discussion courtesy of: Helstein

You could use different classes for the different bgColors, or add a 2nd class to the groups and put the bgColor in those classes (if you have some purpose they must all have aggregated class).

<ul>
    <li></li>
    <li class="aggregated bg1"></li>
    <li class="aggregated bg1"></li>
    <li class="aggregated bg1"></li>
    <li></li>
    <li class="aggregated bg2"></li>
    <li class="aggregated bg2"></li>
    <li class="aggregated bg2"></li>
    <li></li>
    <li class="aggregated bg3"></li>
    <li class="aggregated bg3"></li>
</ul>
Discussion courtesy of: Nick Rolando

This recipe can be found in it's original form on Stack Over Flow.