1

I'm trying to create a sidebar which contains 2 sticky elements. The issue is when the screen size is changed, the elements start to overlapping each other. I wanted to find a way to prevent that overlapping and add some minimal 'margin between' them.

body {
  height: 200vh;
}

.sidebar {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100vh;
}

.topSticky {
  position: sticky;
  top: 2rem;
  padding-bottom: 2rem;
  width: 100px;
  height: 100px;
  border: 1px solid black;
}

.bottomSticky {
  position: sticky;
  bottom: 2rem;
  width: 100px;
  height: 100px;
  border: 1px solid black;
}
<div class="sidebar">
  <aside class="topSticky">Top sticky</aside>
  <aside class="bottomSticky">Bottom sticky</aside>
</div>

I also tried several ways to detect collisions but it was too complex to observe and cover all cases.

There are a few issues and limitations -

  • The bottom element should be always pushed to the bottom, even when scrolling.
  • The upper element has a dynamic height which I observe for any change.
  • The margin between the elements should be reduced when scrolling down(that's naturally happens) but overlapping should be avoided. the margin between them should always be at lease 1rem.

How can I achieve that behaviour? In essence, I should find a way to avoid the overlapping.

Thanks.

Or Ben-Yossef
  • 399
  • 2
  • 17

1 Answers1

0

I made a fiddle. Is this what you are trying to achieve?

https://jsfiddle.net/g7y04dv5/

I only modified the JavaScript but made some styling changes via JavaScript to make it visually more clear that is happening...

// get the sticky elements and their container
const first = document.querySelector('.topSticky');
const second = document.querySelector('.bottomSticky');
const sideBar = document.querySelector('.sidebar');

// make some temporary styling amends so we can see what is happening better
sideBar.style.background = 'linear-gradient(20deg, pink, #6275ff)';
sideBar.style.height = '2000px';
sideBar.style.borderBottom = '300px solid beige';
document.querySelector('body').style.margin = 0;

function stickyMe() {
    const aRem = 16; // roughly a rem
    const marginBetween = aRem * 2; // roughly 2 rem
    
    const containerHeight = window.innerHeight; // height of the window
    const firstHeight = first.offsetHeight; // height of first sticky element
    const secondHeight = second.offsetHeight; // height of second sticky element
    const minimimGap = firstHeight + secondHeight + marginBetween + (aRem * 4); // height of both sticky elements plus their gaps between eachother and the window
            
    if (containerHeight <= minimimGap) { // if the window height is less or equal to the minimimGap
        const newTopPosition = containerHeight - minimimGap;
        first.style.transform = 'translateY(' + newTopPosition + 'px)'; // pull the first sticky element up by the amount smaller the window is compared to the minimumGap
    }
    else {
        first.style.transform = 'none'; // if the gap is large enough for the 2 elements to not overlap then return to normal state
    }
}

window.addEventListener('DOMContentLoaded', stickyMe);;

window.addEventListener('scroll', stickyMe);

window.addEventListener('resize', stickyMe);