Search code examples
htmlcssheaderstickyabsolute

Sticky header doesnt work with z-index, shadow keeps getting hidden by other content


I have that problem, that on my header the box shadow isn't visible because my navigation content lays on top of it, event though my header has a higher z-index. I cant't see what exactly is the issue here, shouldn't this work? Here is an example of my issue:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sticky Element with Navigation</title>
    <style>
        body {
            margin: 0;
            font-family: Arial, sans-serif;
        }

        .sticky-header {
            position: sticky;
            top: 0;
            z-index: 1000; /* Ensure this is high enough */
            background: white;
            box-shadow: 0px 3px 6px rgba(0, 0, 0, .16);            
            padding: 10px;
        }

        .absolute-nav-wrapper {
            position: absolute;
            top: 100%;
            left: 0;
            width: 100%;
            z-index: -1; /* Ensure this is lower than the sticky header */
        }

        .navigation {
            background: white;
            padding: 10px;
        }

        .content {
            padding: 20px;
        }
    </style>
</head>
<body>
    <div class="sticky-header">
        Sticky Header
        <div class="absolute-nav-wrapper">
            <div class="navigation">
                Navigation Content
            </div>
        </div>
    </div>
    <div class="content">
        <p>Page content goes here...</p>
        <p>More content...</p>
    </div>
</body>
</html>

If you remove this part:

<div class="absolute-nav-wrapper">
        <div class="navigation">
            Navigation Content
        </div>
 </div>

the shadow shows up again.


Solution

  • There is no point in trying to use z-index on the heading or the children as they can't go behind (in the z axis sense) their parent.

    If you want to keep that HTML structure then you could put the shadow on an after pseudo element instead of on the element itself. That will ensure that it comes above the children.

    With this adjustment the rest of the CSS can remain as-is.

    This snippet adds some more content so the stickiness can be checked.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Sticky Element with Navigation</title>
      <style>
        body {
          margin: 0;
          font-family: Arial, sans-serif;
        }
        
        .sticky-header {
          position: sticky;
          top: 0;
          background: white;
          padding: 10px;
        }
        
        .sticky-header::after {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          box-shadow: 0px 3px 6px rgba(0, 0, 0, .16);
        }
        
        .absolute-nav-wrapper {
          position: absolute;
          top: 100%;
          left: 0;
          width: 100%;
        }
        
        .navigation {
          background: white;
          padding: 10px;
        }
        
        .content {
          padding: 20px;
        }
      </style>
    </head>
    
    <body>
      <div class="sticky-header">
        Sticky Header
        <div class="absolute-nav-wrapper">
          <div class="navigation">
            Navigation Content
          </div>
        </div>
      </div>
      <div class="content">
        <p>Page content goes here...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
        <p>More content...</p>
      </div>
    </body>
    
    </html>