5

I have the following setup:

<div style="z-index: 10">
      <div>Whatever</div>
</div>

<div style="z-index: 9">
      <div><div>Haaaleluia</div></div>
</div>

Of course... I oversimplified the setup but that's the main idea. The "whatever" div is overlapped by the "Haaaaleluia" div. Of course because the first parent has bigger z-index "whatever" is visible and "haaaleluia" is not.

Without changing the setup (and to be clear that includes keeping the parents z-indexes), how can I make "Haaaaleluia" to be on top?

For those asked for print here it is... also thank you for help: enter image description here

The big bad map is the second div.

The tutorial is the first div.

The panel with orders is child of the map. I need it to be on top. If I set whole map on top, the tutorial is not visible any more. If I keep the map behind the orders panel is not visible any more.

TylerH
  • 20,799
  • 66
  • 75
  • 101
zozo
  • 8,230
  • 19
  • 79
  • 134
  • Let's say yes to js... But can't move children outside parents. As I say... the setup is fixed. – zozo Jul 04 '12 at 13:46
  • Why do you want to have that div on top but not touch the styles of the elements? – Christoph Jul 04 '12 at 14:03
  • 1
    I never understood the questions like: "why would you want to do that?" when the question is not related to scripts or something that might have some other answers or whatever. The answer is always the same: "I got a project, I worked at it for 6 months, I got into this situation, I don't want to work 4-5 hours to remake the whole layout for a damn z-index". – zozo Jul 04 '12 at 14:10
  • A little more code than that would be really helpful. Something we could load into JSFiddle to see what styling constraints you're working under and maybe find a way to work around them. – Phil Jul 04 '12 at 14:14

5 Answers5

8

In short: you can't. It's not possible to have a child of a parent element with a z-index lower than a sibling, and give that child a higher z-index value than the parent's sibling, as the inherited z-index is relative to the parent (see this question for someone coming up against the same thing).

However, depending on your setup, you can remove the z-indices completely, and let the browser place your top div above the one below. You could then play around with giving just the children a z-index value.

Josh Comeau has a great article going into depth on the problem and various solutions/workarounds.

CherryFlavourPez
  • 7,529
  • 5
  • 45
  • 47
  • I had the same idea actually so +1 (I would give you +2 since this is the first pertinent answer :)) )... The thing is that the first div must be on top of the second and the second div child to be on top of the first (it is a panel that opens on mouse over some elements). If I let the browser to play be default the whole second div will be on top of first. The solution would be to change their order but that would totally f*** up the positioning (this is the main reason why I asked the question... would take me hours to remake it and since is all for a damn z-index...). – zozo Jul 04 '12 at 14:07
  • 1
    Thanks. In that case... I think you're out of luck. The only (messy) way to achieve it is going to be to change your markup so those divs are no longer children. Or, depending on what you're trying to achieve, perhaps use generated content or JavaScript: I don't think there is a pure CSS solution. – CherryFlavourPez Jul 04 '12 at 14:26
2

Without changing the locations, z-index, or rearranging any of the elements, the only way I can think of that would allow the div underneath to appear would be to either change the visibility, display or opacity of the div overlapping the one you want to see.

That is, use one of the following CSS styles on the parent div of "Whatever":

visibility: hidden;
display: none;
opacity: 0;

You're basically asking to display an element above another element that has a higher z-index, which defeats the purpose of having a z-index. If you're trying to control how elements overlap, it really should be done with z-index. I would suggest you rethink how your elements are organized (maybe move the "Haaaleluia" div outside of its parent and assign it its own z-index). Otherwise, I might suggest you consider creating a duplicate of "Haaaleluia" to display above "Whatever", which may or may not suit your situation.

Edit: Looking at the image you've provided, changing the parent of the order box to the parent of the tutorial div may work for you. Here is a demo using jQuery that may help illustrate the point - just change the hover event to whatever it is that starts the tutorial. Another option may be to clone the order box to lay on top of the one below, but with a higher z-index (so that the user only sees one, but the clone overlaps everything else). This is assuming that your map div is positioned either absolutely or relatively. Hope that helps.

Zhihao
  • 14,758
  • 2
  • 26
  • 36
  • Imagine that the div on top is smaller than the div behind. Now imagine that in that setup BOTH of them are visible. Does it sound like removing visibility solves the problem? – zozo Jul 04 '12 at 14:14
  • 1
    @zozo I am simply giving you *suggestions* on *possible* options based on what information you've provided in the question and comments. I gave you options, explained why I think your exact request may not work, and suggested alternatives. If you think the answer is too general and does not fit your specific case, then please provide more details. As you said in the question, the example you provided is "oversimplified". I can only work with what you give me. – Zhihao Jul 04 '12 at 14:20
  • Ok ok... removed downvote. Also added print. (Edit the answer so I can remove it). – zozo Jul 04 '12 at 14:21
  • @zozo Thanks, I've updated my answer that may work for the picture you added. Just trying to help. :) – Zhihao Jul 04 '12 at 14:42
  • I know man :). Thanks for trying. Sorry for being a pain... I'm having a bad day. – zozo Jul 04 '12 at 14:47
2

Nice design.

Ok so I'll first say that I believe the solution to your layering problem, as others have already suggested, is moving that box outside of its parent (the map).

But you set some constraints, so I'll try to break as few as possible. I don't know how to do this without breaking any of your constraints. Z-index is inherited (again, others have pointed this out), so you can't break out of your parents' layer with only that tool.

So here's one way you could get the same effect, using javascript. It's ugly, and might cause you more headaches later, but it should at least work:

  1. Find out the absolute position of the div that you want to put on top.
  2. Make a copy of it.
  3. Hide the original (optional if it's opaque).
  4. Insert the copy on top of everything.

If you're using jQuery, you can get elements' position relative to the document with the .offset() function. After that it's fairly simple:

$(document).ready( function() {

    $("a[href='#overlay']").click( function() {
        // 1: get the position
        pos = $('.wrap').offset();
        // 2: make a copy
        halecopy = $('.bottom .wrap').clone();
        // 3: hide the original
        $('.bottom .wrap').css({opacity: 0});
        // 4: Insert new label on top of everything
        $('body').prepend(halecopy);
        // position the new label correctly
        halecopy.css({position:'absolute',
                      top: pos.top,
                      left: pos.left,
                      'z-index': 2});
        // show the "top" layer
        $('.top').fadeIn();
    });

    $("a[href='#hide']").click( function() {
        $('.top').fadeOut( function() {
            // remove the label copy
            halecopy.remove();
            // show the original again
            $('.bottom .wrap').css({opacity: 1});
        });
    });

});​

That script works for me on this markup:

<div class="top">
    <div class="label">
        <p>Whatever</p>
    </div>
</div>

<div class="bottom">
    <div class="wrap">
        <div class="label">
            <p>Haaaleluuuuia!</p>
        </div>
    </div>
</div>

<a href="#overlay">show</a>
<a href="#hide">hide</a>​

With these styles:

.top,
.bottom {
    position: absolute;
    top: 10%;
    left: 3%;
}

.top {
    z-index: 1;
    padding: 2%;
    background: rgba(0, 127, 127, 0.8);
    display:none;
}

.bottom {
    z-index: -1;
    padding: 3%;
    background: rgba(127, 127, 0, 0.8);
}

.label {
    color: #fff;
}

.wrap {
    outline: 1px dashed rgba(127, 0, 0, 0.8);
    background: rgba(127, 127, 127, 0.8);
}

.bottom .label {
    z-index: 10;
}
​

And here's a handly jsfiddle demo.

Phil
  • 869
  • 9
  • 19
  • +1 For effort... Seems impossible without breaking any constraints so I'll probably do something around your answer. – zozo Jul 04 '12 at 15:46
0

Added colour to the div's to demonstrate the layering:

<div style="position:absolute;background:blue;z-index: 10">
      <div>Whatever</div>
</div>

<div style="position:absolute;background:red;z-index: 11">
      <div><div>Haaaleluia</div></div>
</div>
Rhyso
  • 696
  • 2
  • 9
  • 20
  • As I told... I oversimplified. You can see that I didn't specify dimensions, colors, anything. Just I don't know... imagine a green square on top of a bigger red square (the "whatever" is the big one, I need the small one on top). Also I just told that the z-indexes on parents are fixed. – zozo Jul 04 '12 at 13:50
0

This is just an idea which may work.

  1. Get the div having z-index = 9 using jquery.
  2. Then select the 1st child of 1st child of the div having z-index as 9.
  3. Then apply the style as follows:

$(element which you got).attr("style", "position: absolute; z-index: 12;")

The style will be applied to the small element and it will be visible on the red box.

Favonius
  • 13,959
  • 3
  • 55
  • 95
Narendra
  • 3,069
  • 7
  • 30
  • 51
  • 2
    Since it's parent has lower z-index than other parent the element will still be under. Parent z-index is stronger than child. – zozo Jul 04 '12 at 14:46