reversing z-index based from page render order
Asked Answered
S

4

23

Example Markup:

<div class="wrapper">
    <h2>Trigger</h2>
    <div>This is some content</div>
</div>
<div class="wrapper">
    <h2>Trigger</h2>
    <div>This is some content</div>
</div>
<div class="wrapper">
    <h2>Trigger</h2>
    <div>This is some content</div>
</div> 

Example CSS:

.wrapper {z-index: 1}
.wrapper div {display: none; position: absolute;}

Via javascript (jQuery) I'm attaching a click event to each h2 that will then switch the content div to display: block.

The intent is that these are expandable blocks of content that will overlap anything else on the page.

The catch is that I'd like the first one to overlap the second, which would overlap the 3rd in the event that all of them are open.

However, since each one is being rendered AFTER the previous one, the actual stacking order is reversed (The last content div created end sup overlaying the previously created once).

Is there a clever way of reversing this behavior with CSS/HTML? Or is the solution to let the page render, then via javascript, grab all of the content divs in order and give them each a z-index in reverse order?

UPDATE:

Here's some more specific markup:

<div style="padding: 10px;">Hello World
    <div style="position: relative; top: -5px;">
        <div style="position: absolute; background: yellow;"><p>This</p><p>is</p><p>overlapping</p></div>
    </div>
</div>
<div style="padding: 10px;">Hello World
    <div style="position: relative; top: -5px;">
        <div style="position: absolute; background: orange;"><p>This</p><p>is</p><p>overlapping</p></div>
    </div>
</div>
<div style="padding: 10px;">Hello World
    <div style="position: relative; top: -5px;">
        <div style="position: absolute; background: red;"><p>This</p><p>is</p><p>overlapping</p></div>
    </div>
</div>

The following markup will produce 3 divs, each with a colored div overlapping. Due to the render order, the last absolutely positioned DIV (red) will be on top of the one before it (orange).

I can't figure out what type of z-indexes I need to apply to get the FIRST colored overlapping div to be on top. The order from top-to-bottom in terms of z-index should mirror the markup (yellow on top, red on bottom).

This is, of course, reverse of the standard.

I'm willing to use javascript to fix this post-display but I'm still struggling for the exact CSS that I need to apply via javascript. Is what I'm after doable?

Sihonn answered 26/2, 2010 at 21:59 Comment(2)
I would LOVE to see an answer to this too! I have the exact same problem except I won't know ahead of time how many there are to stack!Lorolla
It would be cool if css3 functions could be used as values for z-index. I.E.: counter-increment: my-counter; z-index: counter(my-counter, decimal); OR z-index: calc(xpos+1), but I can't make it work.Systematology
A
18

Here is SASS function for the top answer:

@for $i from 1 through 10 {
   &:nth-child(#{$i}) {
     z-index: #{10 - $i};
   }
}
Aglimmer answered 13/4, 2016 at 21:14 Comment(0)
S
16

So still no answer here, i just did something similar, even though my workaround is 100% hack, if anyone else comes to this page, it did work!

#nav ul li:nth-child(1) {
        z-index:10; 
    }
    #nav ul li:nth-child(2) {   
        z-index:9;  
    }
    #nav ul li:nth-child(3) {
        z-index:8;  
    }
    #nav ul li:nth-child(4) {   
        z-index:7;  
    }
    #nav ul li:nth-child(5) {
        z-index:6;  
    }
    #nav ul li:nth-child(6) {   
        z-index:5;  
    }

I just had that and as long as i didn't get over 10 elements it seems to work...

Sherlene answered 11/8, 2011 at 22:20 Comment(3)
This is actually a great solution because it requires no computation on the client side once loaded as opposed to javascript. The only thing to make it 0% hack is to use SASS or LESS to generate these properties rather than hard-coding them and then wrapping it in a mixin of some kind... which is what I am going to do now :). Thanks.Lipscomb
Done this thing with SASS - gist.github.com/ssidelnikov/6271776. Hope it'll be useful for someone.Brashy
This only works if it's direct children you want to set the z-index of. I think the original question, though a little unclear, was trying to affect the z-index of the inner (position: absolute) divs, which would not be possible with nth-child. I was looking for a way to set the z-index of certain elements, across the page, probably not possible.Disarm
H
13

Shiny new CSS flexbox technology makes this a bit easier, but the downside is the actual content will be reversed. This doesn't have to be a big problem, it's just semantically weird.

In short: wrap everything in a container with these styles:

display: flex;
flex-direction: column-reverse;

See the fiddles for a working example (hover over the wrapper elements to see the action).

It's useful if you don't want to rely on javascript to dynamically check z-indexes every time you update the content. If the <div class="wrapper"> elements are inserted on the fly (or any other reason specific styles cannot be set in advance) The CSS rules in the example should be enough to take care of the z-indexes IF you insert the <div>s in reverse order.

This is your current setup: http://jsfiddle.net/dJc8N/2/

And this is the same HTML, with added CSS (notice the numbers in the <h2> tags): http://jsfiddle.net/Mjp7S/1/

EDIT:

The CSS I posted is probably not ready to be copy-pasted yet. This, however, is:

display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: -o-flex;
display: flex;
-webkit-flex-direction: column-reverse;
-moz-flex-direction: column-reverse;
-ms-flex-direction: column-reverse;
-o-flex-direction: column-reverse;
flex-direction: column-reverse;
Hypertrophy answered 15/1, 2013 at 21:38 Comment(1)
This is a great solution! It wasn't working in IE11 then I noticed there were a few mistakes in the definition of the display properties for older browser support. Here's the solution by css-tricks: css-tricks.com/using-flexbox and I updated the fiddle: jsfiddle.net/Mjp7S/8 which now works in IE11. Thanks again.Kumar
G
1

I had exactly this problem, but an indeterminate number of elements, and possibly too many to make the CSS hack posted by jamie-wilson feasible. Also, since my page is generated dynamically with PHP, I didn't want to fuss with reversing the order of everything in the DOM and using flexbox the way Sandy Gifford suggested. I found an extremely simple and elegant jQuery solution to use instead:

$(document).ready(function() {

  var item_count = $('your-selector').length;

  for( i = 0; i < item_count; i++ )
  {
    $('your selector').eq( i ).css( 'z-index', item_count - i );
  }

});

I can't speak to how performant this is, but with ~35 items I didn't notice any delays.

Gavan answered 10/1, 2018 at 21:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.