21

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?

DA.
  • 39,848
  • 49
  • 150
  • 213
  • 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! – n8wrl Dec 22 '10 at 20:13
  • 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. – skibulk Oct 09 '14 at 18:25

4 Answers4

17

Here is SASS function for the top answer:

@for $i from 1 through 10 {
   &:nth-child(#{$i}) {
     z-index: #{10 - $i};
   }
}
Matthew Leonard
  • 1,965
  • 1
  • 13
  • 10
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...

jamie-wilson
  • 1,925
  • 21
  • 38
  • 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. – Mosselman Jul 10 '13 at 08:46
  • 3
    Done this thing with SASS - https://gist.github.com/ssidelnikov/6271776. Hope it'll be useful for someone. – Stan Sidel Aug 19 '13 at 17:33
  • 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`) `div`s, 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. – Sander Verhagen Feb 05 '17 at 21:34
12

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;
Sandy Gifford
  • 7,219
  • 3
  • 35
  • 65
Dori
  • 1,035
  • 1
  • 12
  • 22
  • 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: https://css-tricks.com/using-flexbox/ and I updated the fiddle: http://jsfiddle.net/Mjp7S/8/ which now works in IE11. Thanks again. – pmrotule Nov 20 '16 at 09:06
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.

Nino Filiu
  • 16,660
  • 11
  • 54
  • 84
dannymcgee
  • 621
  • 2
  • 9
  • 16