Search code examples
jqueryhtmlcsssticky

Sticky Header within a Scrollable Container


There is a bunch of questions about the sticky elements in DOM and wide range of libraries to take care of it, for example:

jquery.pin, sticky-kit and many more

but the problem with all of them is that they only work with the whole body being scrolled, and with restriction that the parent container must have default overflow setting.

enter image description here

The example page of Sticky-kit shows perfectly what I need. Just that in their case their case they actually use an iframe. In mine, it's a Div with overflow: auto (it's an app with flexbox layout with fixed header, footer and left menu, while the main content scrolls).

So I want the red box 'stick me' to stay there when I scroll the gray box. The green elements have no scroll and they never move. My requirements:

  • The body doesn't scroll
  • No iframes
  • I'd prefer no timeout running every 50ms

So far I can see several solutions:

  • position:fixed on the red box, and a) duplicate its content (not an option) b) dynamically adjust the margin/padding of the gray container to force elements to stay below the red box (perfect but the box may expand, and its not easy to monitor its height and readjust the margin). Like this one, but the header height might change: http://jsfiddle.net/KTgrS/

  • position: absolute on the red box, and readjust it on the scroll event of the gray box. Possible, but again the scroll doesn't provide the scroll 'delta', and getting it is kind of sketchy.

Any other ideas or way to make the ones above feasible for actual production use? Support for the recent browsers is enough.


Solution

  • Correct answer

    To easily accomplish this:

    $('.greybox').on('scroll',function(event){
      $('.redbox').css({top: $(this).scrollTop()});
    });
    

    Original answer:

    it's easier to put both red and grey in a container at the same level.

    <div class="container">
      <div class="redbox"></div>
      <div class="greybox"></div>
    </div>
    

    for styling:

    .container
    {
      position: relative;
      width: ...px;
      height: ...px;
    }
    .redbox
    {
      position: absolute;
      top: 0px;
      height: 20px;
      left: 0px;
      right: 0px;
      background: red;
      z-index: 1;
    }
    .greybox
    {
      position: absolute;
      top: 0px;
      left: 0px;
      width: 100%;
      height: 100%;
      overflow: auto;
      padding-top:  20px; // height of the redbox
      box-sizing: border-box;
      z-index: 0;
    }
    

    now redbox looks like it's sticky, but you don't need any JS or sticky stuff, at all :-)