Search code examples
htmlcsscss-positionz-index

How to create a fader and bring an arbitrary element in front (to draw attention) in HTML5/CSS3?


I have a website and I'd like to have a mechanism where I create a 50% transparent black fader in front of everything except one element (no, the fader does not contain the child element) for the user to focus on that particular element for a brief period of time.

I've started with creating a fader with the following properties:

position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.50);
z-index: 1000;

When I'm not using it, I add a class which sets it's z-index to -1 and it's hidden. When I remove the class, it's shown again. I can even add CSS animations to it. So far so good.

Now, suppose that I have an element, independent of this fader div, that I'd like to bring to front.

I've added z-index: 1001 and nothing happened. Then, I've learned that I needed to add relative or absolute positioning to the element for z-index to work. I've added position: relative and it still doesn't work. I'm sure something else is not overriding the z-index or positioning properties. I confirm that my fader has computed absolute positioning and z index of 1000, and also the target object has a computed relative positioning and a z index of 1001. But it target is still hidden behind the fader.

Why?

(I've seen other questions regarding similar issues, but I haven't found an answer to this case in any of them. Most of them tell to use positioning to make z index work which I'm already doing.)


Solution

  • The z-index only affects elements that are placed other than static, (so either, absolute, relative, or static).

    If no z-index is given the flow of the document specifies the stacking. In this demo, the second div stacks above the first one (natural flow).

    div {
      position: absolute;
      top: 0; left: 0;
      width: 100px;
      height: 100px;
    }
    #one {
      background: blue;
    }
    #two {
      top: 30px; left: 30px;
      background: red; 
    }
    <div id="one"></div>
    <div id="two"></div>

    If we want to change that, we need to define a z-index:

    div {
      position: absolute;
      top: 0; left: 0;
      width: 100px;
      height: 100px;
    }
    #one {
      background: blue;
      z-index: 1;
    }
    #two {
      top: 30px; left: 30px;
      background: red; 
    }
    <div id="one"></div>
    <div id="two"></div>

    But you got that part already.

    The tricky part is when you use absolute or relative positions to both parents and child elements. The key is that the z-index or a child can never be greater than it's parent..

    In the following code #one is a child of #parent.

    #parent has a z-index of 10
    #one has a z-index of 30
    #two has a z-index of 20

    So, you might expect the order (behind to above) to be

    #parent > #two > #one
    but since the z-index of #one can't be bigger that it's parent, it will be
    #parent > #one > #two

    #parent {
      position: relative;
      width: 120px;
      height: 120px;
      background: yellow;
      top: 0; left: 0;
      z-index: 10
    }
    #one {
      position: absolute;
      width: 100px;
      height: 100px;
      top: 0; left: 0;
      background: blue;
      z-index: 30;
    }
    #two {
      position: absolute;
      top: 40px; left: 40px;
      width: 100px;
      height: 100px;
      background: red;
      z-index: 20;
    }
    <div id="parent">
      <div id="one"></div>
    </div>
    <div id="two"></div>