user3590712
user3590712

Reputation:

Advanced nth-child selection

I am attempting to figure out a nth-child selection rule that will select the "remainder" of division by three. To explain here is a visual diagram.

EDIT: Providing more examples for clarity.

div1
(should select div1)

div1     div2
(should select div1 and div2)

div1     div2     div3
(should select nothing)

div1     div2     div3    div4
(should select div4)

div1     div2     div3    div4    div5
(should select div4 and div5)

div1     div2     div3     div4     div5     div6
(should not select anything)

div1     div2     div3     div4     div5     div6     div7
(should select div7)

etc...

I believe that this may be possible, but am unable to figure it out.

Upvotes: 1

Views: 659

Answers (4)

user3590712
user3590712

Reputation:

I believe I have solved it to my satisfaction, despite having to write two different groupings of css. The trick is that you can use multiple selectors in the same line, which is the equivalent of making Unions between the set selections.

Working example at http://jsfiddle.net/MY4cD/

A more complete solution (and expandable to other multiples besides three is below.

Given the following HTML ( and for any number of )

<div class="container">
    <div class="cell">1</div>
    <div class="cell">2</div>
    <div class="cell">3</div>
    <div class="cell">4</div>
    <div class="cell">5</div>
    <div class="cell">6</div>
    <div class="cell">7</div>
    <div class="cell">8</div>
</div>

The following CSS would create rows of three with the "remainder" divs highlighted red.

    .cell {
        width: 33.33%;
    }

    .cell:nth-last-child(-n+2):nth-child(3n+1):nth-last-child(1){
        background:red;
    }

    .cell:nth-last-child(-n+2):nth-child(3n+1):nth-last-child(2){
        background:red;
    }

    .cell:nth-last-child(-n+2):nth-child(3n+2):nth-last-child(1){
        background:red;
    }

If you wanted to have 4 divs per row and select the remainder again you could use the following CSS

    .cell {
        width: 25%;
    }

    /* accounts for when there is 1 remainder */
    .cell:nth-last-child(-n+3):nth-child(4n+1):nth-last-child(1){
        background:red;
    }

    /* accounts for the first of 2 remainders */         
    .cell:nth-last-child(-n+3):nth-child(4n+1):nth-last-child(2){
        background:red;
    }

    /* accounts for the second of 2 remainders */
    .cell:nth-last-child(-n+3):nth-child(4n+2):nth-last-child(1){
        background:red;
    }

    /* accounts for the first of 3 remaidners */
    .cell:nth-last-child(-n+3):nth-child(4n+1):nth-last-child(3){
        background:red;
    }

    /* accounts for the second of 3 remainders */
    .cell:nth-last-child(-n+3):nth-child(4n+2):nth-last-child(2){
        background:red;
    }

    /* accounts for the third of 3 remainders */
    .cell:nth-last-child(-n+3):nth-child(4n+3):nth-last-child(1){
        background:red;
    }

In this way, you can see the pattern will grow ever more complex the higher you go, but it is certainly possible for any number.

I have used this pattern along with media queries to simulate the effects of the new CSS flex-flow: row wrap; command with using floats for cross browser compatability. You can see the full demo of this here : http://codepen.io/msorrentino/full/chHnu/

Upvotes: 0

Jonathan Lonowski
Jonathan Lonowski

Reputation: 123453

:nth-child() :nth-last-child(), and the general sibling selector (~) can be combined to match elements following the last group of 3.

div:nth-child(3n):nth-last-child(-n+3) ~ div {
    /* ... */
}

http://jsfiddle.net/akzzM/

With the 3rd example of 7 divs:

  • nth-child(3n) matches every 3rd <div> -- matching 3 and 6.
  • nth-last-child(-n+3) matches the last 3 siblings -- matching 5, 6, and 7.
  • Combined, they'll only match the last interval of 3 -- matching 6.

Then ~ div matches any siblings that follow (7).


To match the 1st and 2nd when there isn't a 3rd, you can also match the :first-child if it's one of the last 2 and :last-child if it's one of the first 2:

div:nth-child(3n):nth-last-child(-n+3) ~ div,
div:first-child:nth-last-child(-n+2),
div:last-child:nth-child(-n+2) {
    /* ... */
}

http://jsfiddle.net/JEST3/

Upvotes: 4

Paulie_D
Paulie_D

Reputation: 114989

As far as I can tell there is no single selector that will let you do this.

However a combination of nth-last-child and an overide with nth-child will get you there.

CSS

li:nth-last-child(-n+2) {color:red;}

li:nth-child(3n) {color:black;}

li:nth-child(1),
li:nth-child(2),
li:nth-child(3) {color:black;}

Jsfiddle Demo

Upvotes: 1

Barun
Barun

Reputation: 4431

This can be the solution for your problem:

div:not(:nth-child(3n)):not(:nth-child(1)):not(:nth-child(2)) {
    background-color: #38f;
}

Upvotes: 0

Related Questions