Search code examples
cssz-index

CSS z-index not working with position relative


I am having no luck with getting z-index to work. While this all seems pretty simple. I just need to show some content overwriting some other content. This is to create a simple dropdown control, so that the dropped down menu is temporarily shown without the next content moving down, and later back up.

Here is my code, simplified, and stand-alone:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Z-Axis</title>
    <style>
        #main_div {
            position: relative;
            z-index: 0;
            top: 0px;
            left: 0px;
        }
        .dropdown {
            position: relative;
            z-index: 1;
            top: 0px;
            left: 0px;
        }
    </style>
</head>
<body>
    <div id="main_div">
        <p>line 1 of text</p>
        <p>line 1 of text</p>
        <p>line 1 of text</p>
        <ul class="dropdown">
            <li>5</li>
            <li>10</li>
            <li>20</li>
        </ul>
        <p>line 2 of text</p>
        <p>line 3 of text</p>
        <p>line 4 of text</p>
        <p>line 5 of text</p>
        <p>line 6 of text</p>
    </div>
</body>
</html>

As you see, I took care of creating a parent stacking context in the main-div, but this did not help. When I run the above in Firefox or Chrome, the dropdown list is shown, and the lines 2-6 are pushed down the page, instead of hiding behind the dropdown list.

The position has to be relative, because this stuff will be a React component, and be positioned somewhere in a larger page. The dropdown list should be right below Line1, and lines 2-6 should be hiding on a lower z-index plane.


Solution

  • Thing you got wrong was position: relative instead of position: absolute. I changed it and now it works. position: relative makes it only, well, relative, not render regardless or other DOM elements.

    I added background: red so the effect is better visible.

    Your z-index works just fine, but element is still rendered respecting other DOM elements.

    According to MDN:

    • relative: The element is positioned according to the normal flow of the document, and then offset relative to itself based on the values of top, right, bottom, and left. The offset does not affect the position of any other elements; thus, the space given for the element in the page layout is the same as if position were static. This value creates a new stacking context when the value of z-index is not auto. Its effect on table-*-group, table-row, table-column, table-cell, and table-caption elements is undefined.
    • absolute: The element is removed from the normal document flow, and no space is created for the element in the page layout. It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block. Its final position is determined by the values of top, right, bottom, and left.

    Key part

    .dropdown {
        position: absolute;
        ...
    }
    

    Snippet

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>Z-Axis</title>
        <style>
            #main_div {
                position: relative;
                z-index: 0;
                top: 0px;
                left: 0px;
            }
            .list-wrapper {
              position: relative;
            }
            .dropdown {
                position: absolute;
                top: 0;
                left: 0;
                z-index: 1;
                background: red;
            }
        </style>
    </head>
    <body>
        <div id="main_div">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nibh augue, suscipit a, scelerisque sed, lacinia in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus. Phasellus pharetra nulla ac diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nibh augue, suscipit a, scelerisque sed, lacinia in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus. Phasellus pharetra nulla ac diam.
          <div class="list-wrapper">
            <p>line 1 of text</p>
            <ul class="dropdown">
                <li>5</li>
                <li>10</li>
                <li>20</li>
            </ul>
            <p>line 2 of text</p>
            <p>line 3 of text</p>
            <p>line 4 of text</p>
            <p>line 5 of text</p>
            <p>line 6 of text</p>
          </div>
        </div>
    </body>
    </html>