skip to Main Content

Given a HTML element with some silibings:

    <div id=parent>
        <div></div>
        <div></div>
        <div></div>
        ...
        <div id=fourthToLast></div>
        <div></div>
        <div id=penultimate></div>
        <div></div>
    </div>

The penulimate and the fourthToLast silibing are special:
One or the other – but never both – should be shown at different widths,
depending on media breakpoints and total number of silibings.

In the CSS code I put pseudo code selectors:

silibingNrOf(#penultimate) mod x = y

Example: If parent has a total of 15 silibings, then silibingNrOf(#penultimate) is 14.
silibingNrOf(#penultimate) mod 3 would equal 2.

I need the correct CSS selector syntax for this problem and can’t find out how to do it.

    #fourthToLast, #penultimate { display: none; }

    @media screen and (min-width: 400px) {
        
        if silibingNrOf(#penultimate) mod 2 = 0 {
            #penultimate { width: 25%; display: block; }
        }
        
        @media screen and (min-width: 800px) {
        
            #penultimate { display: none; }
        
            if silibingNrOf(#penultimate) mod 3 = 2 {
                #penultimate { width: 33%; display: block; }
            }

            if silibingNrOf(#penultimate) mod 3 = 0 {
                #fourthToLast { width: 16.666%; display: block; }
            }   
        
       }
    }

2

Answers


  1. Chosen as BEST ANSWER

    Given the structure from the question and all it's variations with 1 to 7 elements (+ the extra elements 'penultimate' and 'fourthToLast'). The empty elements formerly labeled 'penultimate' and 'fourthToLast' don't need an ID for this.

    
        <div id=parent1>
            <div></div>
            <div>Content 1</div>
        </div>
        
        <div id=parent2>
            <div></div> 
            <div>Content 1</div>
            <div></div> 
            <div>Content 2</div>
        </div>
        
        <div id=parent3>
            <div>Content 1</div>
            <div></div>
            <div>Content 2</div>
            <div></div>
            <div>Content 3</div>
        </div>
        
        <div id=parent4>
            <div>Content 1</div>
            <div>Content 2</div>
            <div></div>
            <div>Content 3</div>
            <div></div>
            <div>Content 4</div>
        </div>
        
        <div id=parent5>
            <div>Content 1</div>
            <div>Content 2</div>
            <div>Content 3</div>
            <div></div>
            <div>Content 4</div>
            <div></div>
            <div>Content 5</div>
        </div>
        
        <div id=parent6>
            <div>Content 1</div>
            <div>Content 2</div>
            <div>Content 3</div>
            <div>Content 4</div>
            <div></div>
            <div>Content 5</div>
            <div></div>
            <div>Content 6</div>
        </div>
        
        <div id=parent7>
            <div>Content 1</div>
            <div>Content 2</div>
            <div>Content 3</div>
            <div>Content 4</div>
            <div>Content 5</div>
            <div></div>
            <div>Content 6</div>
            <div></div>
            <div>Content 7</div>
        </div>
    

    The task is

    Initially hide the two (non-core) extra child elements,       
    which will always be the penultimate and the fourth-to-last child.    
    
    if 400px <= screen width < 800px
        if count of core childs is odd
            display the penultimate child at 25% width
    
    if screen width >= 800px
        if count of core childs mod 3 = 2
            display the penultimate child with 16.66% width
    
        if count of core childs mod 3 = 1
            display the fourth-to-last child with 33.33% width
    

    To be solved without javascript and without functions not widely supported by all browsers (:has() / Firefox).

    Solution:

    :is(#parent1, #parent2, #parent3, #parent4, #parent5, #parent6, #parent7) {
    
        div:nth-last-child(2) {
            display: none;
    
            @media screen and (min-width: 400px) {
                &:is(:first-child, :nth-of-type(even)) {
                    width: 25%;
                    display: block;
                }
                @media screen and (min-width: 800px) {          
                    &:nth-of-type(even) {
                        display: none;
                    }
                    &:is(:first-child, :nth-of-type(3n + 2)) {
                        width: 33.33%;
                        display: block;
                    }
                }
            }
        }
    
        div:nth-last-child(4) {
            display: none;
    
            @media screen and (min-width: 800px) {
                &:nth-child(3n + 1) {
                    width: 16.66%;
                    display: block;
                }
            }
        }
    }
    

    Special thanks go to David Thomas for his very inspiring jsfiddle that put me on track.


  2. Edit: you could use :nth-of-type(3n) for silibingNrOf(#penultimate) mod 3 = 0 and :nth-of-type(3n+2) for silibingNrOf(#penultimate) mod 3 = 2. And obviously :nth-of-type(even) or :nth-of-type(2n) for silibingNrOf(#penultimate) mod 2 = 0 as you’ve already figured out. :nth-child() would also work for this case, and the parameters would be the same. I jumped straight to javascript in my first answer and only thought of this after your comment.

    Previous answer:
    You could do the following in javascript:

    const parent = document.getElementById("parent");
    const parentChildrenCount = parent.childElementCount; 
    if(parentChildrenCount % 2 === 1){
        parent.addClass("even"); // silibingNrOf(#penultimate) mod 2 = 0
    }
    if(parentChildrenCount % 3 === 1){
        parent.addClass("triple"); // silibingNrOf(#penultimate) mod 3 = 0
    }
    else if(parentChildrenCount % 3 === 0){
        parent.addClass("almost-triple"); // silibingNrOf(#penultimate) mod 3 = 2
    }
    

    and then use these classes to select the elements in your sass code. Also, penultimate and fourthToLast could be selected using :nth-last-child pseudoselector.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search