14

I'm doing a little experiment, trying to alternate background colours for nested divs.

This is what I intend to achieve (without the inline styles):

<div style="background: #fff;">
    <div style="background: #000;">
        <div style="background: #fff;">
            <div style="background: #000;">
                and so on...
            </div>
        </div>
    </div>
</div>

I feel like I must be missing something obvious! I tried div:nth-of-type(2n) but this appears to only apply on one level.

This is for an experiment where the divs are generated, so the solution needs to be endless (not something along the lines of div div div div = white). I know it's quite easy with JavaScript, just looking for a pure CSS solution.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
daviestar
  • 4,531
  • 3
  • 29
  • 47
  • That's right, `nth-of-type` works only on the same level. So I'm afraid that what you want doesn't have a CSS solution. Will be checking back for answers though. – Mr Lister Apr 07 '12 at 14:38
  • @AnkitGautam how will that help with the OP's problem? – Mr Lister Apr 07 '12 at 15:00
  • I think it can't be done without additional markup. – mddw Apr 07 '12 at 15:04
  • 1
    @AnkitGautam 'Original Poster/Post' as for the question: can't be done, you're gonna have to do it with JS. It doesn't have to be a heavy operation. – sg3s Apr 07 '12 at 15:12
  • 1
    Such selector does not exist yet. If you want to reduce the size of the HTML code, you can als use attributes: http://jsfiddle.net/fQPXs/ (using `div[x]` and `div[y]`). That's not valid HTML5 though, which require custom attributes to be prefixed with `data-`. The correct way to do it is by using class names: `
    ` `.x{...}`.
    – Rob W Apr 07 '12 at 15:20

2 Answers2

7

As Mr Lister pointed out, nth-of-type works on one level (that of the parent of the selected div).

As far as i know and after looking through the W3C CSS3 Selectors there doesn't appear to be any css selectors for traversing through nesting (except the > selector, which only looks at the direct child of parent).

I would love te be proven wrong though as that could be very usefull.

So the only (css) solution would be the one you already stated: div > div > div {background: white; } Can't you just generate this along with the generation of the div's?

Martijn
  • 15,791
  • 4
  • 36
  • 68
Pirokiko
  • 309
  • 1
  • 6
  • Thanks for your help. It seems strange that this isn't possible just yet. The selector should be named nth-child-of-type. Perhaps we might see syntax in the future which looks like div >(2n) div. – daviestar Apr 09 '12 at 11:40
4

As stated by others, this is not possible in pure CSS. However using js it is quite possible and fairly easy too.

For ease I implemented this in jQuery but you could do with pure JS.

http://jsfiddle.net/sg3s/Suf3p/

I basically made a small jQuery plugin that colors the selector you apply it on with the primary color, and uses the subselect to get a matching child to color with the secondary color and so on until no children matching the subselect are left.

jQuery(function($) {
    $.fn.alternateNestedBgColor = function(subselect, colors) {
        // While not a great optimization, length of the colors array always stays the same
        var l = colors.length;

        // Itterate over all element in possible array
        // jQuery best practice to handle initializing multiple elements at once
        return this.each(function() {
            var $sub = $(this), i = 0; 

            // Executes code, at least once
            do {

                // Set bg color for current $sub element
                $sub.css('backgroundColor', colors[i++ % l]);
                // Set $sub to direct children matching given selector
                $sub = $sub.children(subselect);

            // Will repeat the do section if the condition returns true
            } while ($sub.length > 0);
        });
    };

    // target first div in the body
    // first argument = child selector
    // second argument = array list of colors
    $('body>div').alternateNestedBgColor('div', ['red', 'green', 'blue', 'purple', 'grey']);
});

Update As requested an update detailing how apply and modulo were used.

It's been almost 2 year since I recently posted this. And while working, the solution I made back then was a bit verbose and confusing, as for instance, I never needed apply. I got a little bit more comfortable with scopes, so I revised the function to be much simpler.

The only situation where apply is useful is when you need to pass a value to the this variable inside the function scope. Unless working with classes there aren't a whole lot of situations you should have a need for apply or call. If you want to read up on it I would like to refer you to this answer which explains it in context of classes. The MDN link is a good resource as well (for this and other javascript constructs/concepts).

As for modulo, this is basic math and this question explains the operation quite well. In short it will give you the full integer remainder after dividing a number by another. So 33 % 8 = 1 which you could write as 33-parseInt(33/8)*8 in js though that would be grossly inefficient. The result of the operation will always be 0 (when the number perfectly divides) to the 2nd argument minus 1 (so 7 in my example).

0 % 3 = 0 // technically doesn't exist (as you can't divide 0 with anything) but 0 for practicality in all programming languages afaik(?)
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0 etc...

It's one of those operations which is inherently simple for your CPU, in fact without it being able to do this we wouldn't have computers.

In the javascript revision I've written the selection of the color from the given array as colors[i++ % l].

In writing this would be give me the remainder of i / l and use that integer as an index for the colors array which returns a color for use.

The ++ will add 1 only after returning the value of i for use in the modulo, this behaviour would be reversed if I had written ++i, but that wouldn't work for our purpose here.

For reference here is the MDN article on do...while.

I hope that cleared some things up! :)

Community
  • 1
  • 1
sg3s
  • 9,411
  • 3
  • 36
  • 52
  • With some small modification you could make this match other patterns or work with 3 colors alternating after each other as well. – sg3s Apr 07 '12 at 15:35
  • Heh, I just modified it since it wasn't much work anyway and I like to improve things were possible. – sg3s Apr 07 '12 at 20:34
  • Thankyou for your script. I am using mootools, but I'm sure it will be useful for others. – daviestar Apr 09 '12 at 11:32
  • Even if it's not, its ok, its not every day I get to use a `do {} while ()` :p – sg3s Apr 09 '12 at 11:45
  • Hehe :) I am feeling the same, it's not every day you ask a very simple CSS question that no one has asked before! :D – daviestar Apr 09 '12 at 12:00
  • I don't think it's something no-one has asked before, its just that... nesting is tricky to the untrained mind, and unfortunately its something the creators of the specs take into consideration. – sg3s Apr 09 '12 at 12:07
  • the new(ish) nth selectors are very powerful, but if you constrain them all to one level, in my view, they are quite weak. creating simple styling 'loops' has only been considered in terms of alternate row backgrounds i think, when it is possible to do so much more with them. hopefully it is something we will see in the future. – daviestar Apr 09 '12 at 13:51
  • I'm back here as I'm trying to learn more about do-while loops, and I remembered here was the first time I'd heard of them! Would you mind commenting some of your code? I'm really interested in how you are using `apply` and `modulo` for this problem – daviestar Mar 05 '14 at 08:41