HarshvardhanSharma
HarshvardhanSharma

Reputation: 786

Fix container inside another container on window scroll using pure javascript

I have a container thisSticks that I have to fix in another container stickInContainer on scroll. Basically, replicate CSS sticky behaviour. I could have just used sticky, but it doesn't work in all browsers. So I am making it in pure javascript.

Current Behaviour: In the demo below, grey container should never overlap with blue footer container, but it does.

Expected Behaviour: When the bottom of thisSticks hits top of footer, it should stay there and when user scrolls back up and reaches top of thisSticks, it should stick back to top of stickInContainer till it reaches its initial position.

I can think of incrementing stickyDiv.style.bottom on every scroll after thisSticks bottom hits top of footer.

How will this work, Is there another approach?

window.onscroll = function() {
  myFunction();
}

const stickyDiv = document.getElementById('thisSticks');

const stickyDivHeight = stickyDiv.offsetTop;

function myFunction() {
  if (window.pageYOffset > stickyDivHeight) {
    stickyDiv.style.position = 'fixed';
    stickyDiv.style.top = 0;
  } else {
    stickyDiv.style.position = 'initial';
  }
}
#topSection {
  height: 100px;
}

#stickInContainer {
  height: 800px;
}

#thisSticks {
  width: 100%;
  height: 40px;
  opacity: 0.7;
  background-color: grey;
}

#footer {
  width: 100%;
  background-color: blue;
  height: 500px;
}
<div id='topSection'>Top Section</div>
<div id='stickInContainer'>
  <div id='thisSticks'></div>
</div>
<div id='footer' />

Upvotes: 3

Views: 815

Answers (2)

Temani Afif
Temani Afif

Reputation: 272842

You can add another condition to test when the footer reach the top minus the height of the sticky element. If it's the case you change the top differently:

window.onscroll = function() {
  myFunction();
}

const stickyDiv = document.getElementById('thisSticks');
const footer = document.getElementById('footer');

const stickyDivHeight = stickyDiv.offsetTop;
const Height = stickyDiv.clientHeight; /*height of the sticky element*/

const footerHeight = footer.offsetTop; /*footer offset*/

function myFunction() {
  if (window.pageYOffset > stickyDivHeight ) {
    stickyDiv.style.position = 'fixed';
    stickyDiv.style.top = 0;
  } else {
    stickyDiv.style.position = 'initial';
  }
  
  /*Here the sticky will touch the footer and top will be negative*/
  if(window.pageYOffset>(footerHeight - Height)) {
    stickyDiv.style.top = (footerHeight - Height)-window.pageYOffset + "px";
  }
}
#topSection {
  height: 100px;
}

#stickInContainer {
  height: 800px;
}

#thisSticks {
  left:0;
  right:0;
  height: 40px;
  opacity: 0.7;
  background-color: grey;
}

#footer {
  background-color: blue;
  height: 500px;
}
body {
 margin:0;
}
<div id='topSection'>Top Section</div>
<div id='stickInContainer'>
  <div id='thisSticks'></div>
</div>
<div id='footer' ></div>

Upvotes: 1

CeritT
CeritT

Reputation: 532

You need another condition to check if it hit the bottom of your stickInContainer. You can achieve this in different ways, you can check style bottom as you mentioned or footer top maybe, but since you have a container, I have prefered the approach below.

I edited code your a little by defining a limit that points to your container's bottom var stickyLimit = stickyDivContainer.offsetHeight + stickyDivContainer.offsetTop - stickyDiv.offsetHeight

and added a condition to your into your if block to make stickyDiv stop and wait there.

  else if(window.pageYOffset>=stickyLimit ){
    stickyDiv.style.position = 'static';
    stickyDiv.style.top = stickyLimit;
  }

I hope this is what you are looking for, i also suggest making some transition effect to stickyDiv where it changes its position behaviour, because checking scrolls from offset values and making changes to position style doesn't feel smooth.

window.onscroll = function() {
  myFunction();
}

const stickyDiv = document.getElementById('thisSticks');

const stickyDivContainer = document.getElementById('stickInContainer');

const stickyDivHeight = stickyDiv.offsetTop;

function myFunction() {

  var stickyDivBottom = stickyDiv.scrollTop + stickyDiv.offsetHeight;
  var stickyLimit = stickyDivContainer.offsetHeight + stickyDivContainer.offsetTop  - stickyDiv.offsetHeight;

  if (window.pageYOffset > stickyDivHeight && window.pageYOffset<stickyLimit ) {
    stickyDiv.style.position = 'fixed';
    stickyDiv.style.top = 0;
  }else if(window.pageYOffset>=stickyLimit ){
    stickyDiv.style.position = 'static';
    stickyDiv.style.top = stickyLimit;
  }else {
    stickyDiv.style.position = 'initial';
  }
}
#topSection {
  height: 100px;
}

#stickInContainer {
  height: 800px;
}

#thisSticks {
  width: 100%;
  height: 40px;
  opacity: 0.7;
  background-color: grey;
}

#footer {
  width: 100%;
  background-color: blue;
  height: 500px;
}
<div id='topSection'>Top Section</div>
<div id='stickInContainer'>
  <div id='thisSticks'></div>
</div>
<div id='footer' />

Upvotes: 0

Related Questions