Search code examples
htmlcsssticky

Stick an element out of its container


I'd like to have a header with one sticky element and one non-sticky element. Hence, the structure would be something like this:

body {
  margin: 0;
  height: 2000px;
}

header {
  position: static;
  border: 1px solid blue;
  overflow: visible;
}

.sticky-yes {
  position: sticky;
  top: 0;
  border: 1px solid blue;
}

.sticky-no {
  position: relative;
  top: 0;
  border: 1px solid orange;
}
<header>
  <div class="sticky-yes">Sticky</div>
  <div class="sticky-no">Not sticky</div>
</header>
<div>... Rest of the webpage ...</div>

The header sits as a direct child of the body.

As far as I know, sticky elements want to stick to the nearest ancestor with a "scrolling mechanism". And I can "ignore" the parent element by giving it position: static;

I also added overflow: visible; to the parent after reading this related question: CSS - Allow an div to stick out of its parent

But this snippet won't work.

I am constrained to use it with that markup, I cannot move the sticky element outside of the header.

What approach can I take?


Solution

  • You can do this with a bit of creative CSS. Adds a bit of maintenance but does stick the element. Note here I sized both elements and used that as the base height of the header. I also used box-sizing to avoid issues with this is zoomed in a browser.

    body {
      margin: 0;
      padding: 0;
      font-size: 16px;
      height: 2000px;
      --sticky-height: 3rem;
      --non-sticky-height: 2rem;
      --header-height: calc(var(--sticky-height) + var(--non-sticky-height));
    }
    
    header {
      box-sizing: border-box;
      border: 1px solid cyan;
      height: var( --header-height);
    }
    
    .sticky-yes {
      box-sizing: border-box;
      position: fixed;
      top: 0;
      border: 1px solid blue;
      height: var(--sticky-height);
    }
    
    .sticky-no {
      box-sizing: border-box;
      position: relative;
      top: var(--sticky-height);
      height: var(--non-sticky-height);
      border: 1px solid orange;
    }
    <header>
      <div class="sticky-yes">Sticky</div>
      <div class="sticky-no">No</div>
    </header>