Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
<script src="http://yui.yahooapis.com/3.10.0/build/yui/yui.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div class="container">
  <div class="wrapper">
    <div class="header">Header 1</div>
    <div class="content">Scroll Down.</div>
    <div class="header">Header 2</div>
    <div class="content">Scroll Down.</div>
    <div class="header">Header 3</div>
    <div class="content">Scroll Down.</div>
    <div class="header">Header 4</div>
    <div class="content">Scroll Down.</div>
    <div class="header">Header 5</div>
    <div class="content" style="height:200px">The End.</div>
  </div>
</div>
</body>
</html>
 
// Hack for prototype to make sure the DOM is rendered in jsbin.
setTimeout(function() {
  
  var headers = document.querySelectorAll('.header'),
      headersLength = headers.length,
      wrapper = document.querySelector('.wrapper'),
      stackingOffset = 0;
  Array.prototype.forEach.call(headers, function(header, index) {
    // Set up the header element for sticking to the top
    header.originalOffsetTop = header.offsetTop;
    header.stackingOffset = stackingOffset;
    header.placeholderElement = document.createElement('div');
    header.placeholderElement.style.height = header.clientHeight + 'px';
    
    // Set up the header element for sticking to the bottom
    // working in reverse
    var bottomHeader = headers[headersLength - index - 1];
    // Set a sane default so we don't break later calculations
    if (bottomHeader.bottomStackingOffset === undefined) {
      bottomHeader.bottomStackingOffset = 0; 
    }
    if (bottomHeader.offsetTop > wrapper.clientHeight - bottomHeader.clientHeight) {
      bottomHeader.bottomStackingOffset = header.stackingOffset;
      bottomHeader.style.bottom = header.stackingOffset + 'px'; 
    }
    
    stackingOffset += header.clientHeight;
  });
  // If we add this class during the above loop it messes up the
  // offset calculations so we need to make one more loop unfortunately
  Array.prototype.forEach.call(headers, function(header, index) {
    if (parseInt(header.style.bottom, 10) >= 0) {
      header.classList.add('stuck-bottom');
    }
  });
  
  function stickHeaders(e) {
    Array.prototype.forEach.call(headers, function(header, index) {
      var topOffset = 0;
      if (index > 1) {
        topOffset = header.clientHeight * (index - 1); 
      }
      
      // sticking to top
      if (e.target.scrollTop + header.clientHeight + topOffset > header.originalOffsetTop) {
        wrapper.insertBefore(header.placeholderElement, header);
        header.classList.add('stuck');
        header.style.top = header.stackingOffset + 'px';
      } else {
        if (header.placeholderElement.parentElement !== null) {
          wrapper.removeChild(header.placeholderElement);
        }
        header.classList.remove('stuck');
      }
      
      // sticking to bottom
      if (e.target.scrollTop + wrapper.clientHeight - header.bottomStackingOffset - header.clientHeight > header.originalOffsetTop) {
        if (header.classList.contains('stuck-bottom')) {
          console.log(header);
          header.classList.remove('stuck-bottom');
          header.style.bottom = null;
        }
      } else {
        header.style.top = null;
        header.classList.add('stuck-bottom');
        header.style.bottom = header.bottomStackingOffset + 'px';
      }
    });
  }
wrapper.addEventListener('scroll', stickHeaders);
}, 1000);
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
hatchpro
0viewers