4

I have a menu on the left that I want to be always sticky, I'm using javascript for that for IE11 support.

The problem I'm having is that the right div goes to the left when it's sticky and doesn't keep it's position, the second issue is that the .content div width grows when the right div is sticky.

For the javascript part, I don't know how to make the right div to stop when it reaches the footer.

EDIT:

I managed to solve the second issue, the code is updated, I also tried to add a right value for the right div so it sticks in its initial vertical position, but that's not working because it changes when the screen gets resized.

How can I solve this?

Edit 2:

For the javascript issue I found this post which helped me resolve my issue:

Make sticky/fixed element stop at footer

var sticky = document.getElementsByClassName("sticky-element")[0];
var stickyAnchor = sticky.parentNode;
var state = false;

function getAnchorOffset() {
    return stickyAnchor.getBoundingClientRect().top;
}

updateSticky = function (e) {
    if (!state && (getAnchorOffset() < 0)) {
      sticky.classList.add("is-sticky");
      sticky.parentElement.classList.add("has-sticky");
      state = true;
    } else if (state && (getAnchorOffset() >=0 )) {
      sticky.classList.remove("is-sticky");
      sticky.parentElement.classList.remove("has-sticky");
      state = false;
    }
}

window.addEventListener('scroll', updateSticky);
window.addEventListener('resize', updateSticky);

updateSticky();
.main-wrapper {
    margin: 48px 48px 0 48px;
    max-width: 1366px;
}

.wrapper {
    width: 100%;
    display: flex;
    justify-content: space-between;
    position: relative;
}

.wrapper.has-sticky .content{
    margin-right: calc(199px + 72px);
}

.content {
    flex: 0 1 1040px;
    width: calc(1040px - 72px);
    min-width: 1%;
    margin-right: 72px;
    height: 1200px;
    background-color: #e6e9f0;
}

.nav-menu {
    position: static;
    flex: 0 1 199px;
    width: 199px;
    min-width: 199px;
    color: white;
    height: 300px;
    background-color: #04246a;
    right: 10%;
}

footer {
  background-color: yellow;
  height: 300px;
  margin-top: 50px;
}

.is-sticky {
    top: 0;
    position: fixed;
}
<div class="main-wrapper">
  <div class="wrapper">
    <div class="content">
      Main content
    </div>
    <div class="nav-menu sticky-element">
      <nav>
        Side content
      </nav>
    </div>
  </div>
  <footer>
    Footer content
  </footer>
</div>
Renaud is Not Bill Gates
  • 1,684
  • 34
  • 105
  • 191
  • position sticky is like position absolute, meaning that the element will be removed from the initial position that it had so the other elements will fill that empty position. Same goes for the width, in the beginning there are 2 elements and they share the width, but once an element has position sticky it will get removed so the other elements will use full the full width – Why u do dis Apr 02 '21 at 11:14
  • you are using % for the width which can change based on how many elements there are, if you want the element to have a fixed width then give it a width with px. eg width:50px – Why u do dis Apr 02 '21 at 11:16
  • Worth a look - `position:sticky;` and `overflow` REALLY don't like each other. This has gotten me a couple times when working with sticky: https://stackoverflow.com/a/47878455/241153. You may have to look all the way up your DOM tree for a culprit. Doesn't sound like your problem but double check. – serraosays Apr 06 '21 at 02:35
  • @serraosays if it wasn't for IE11, using `position: sticky` would save me a lot of time xD – Renaud is Not Bill Gates Apr 06 '21 at 07:18

2 Answers2

3

Are you looking for this?

The problem on your code is that whenever you set the position of your right div to fixed it then looks for its relative parent and jumps to the upper left position inside the parent. In your case, the parent div was the .wrapper, that's why it keeps on jumping to the left side and overlaps your main content div.

I added a parent container for the .nav-menu so it will still be in the same position when scrolling. With this, your .nav-menu element won't be using the .wrapper as its main parent. This will create a smooth scroll without noticing any change in position.

Happy coding!

var sticky = document.getElementsByClassName('sticky-element')[0];
var stickyAnchor = sticky.parentNode;
var state = false;

function getAnchorOffset() {
  return stickyAnchor.getBoundingClientRect().top;
}

updateSticky = function (e) {
  if (!state && getAnchorOffset() < 0) {
    sticky.classList.add('is-sticky');
    state = true;
  } else if (state && getAnchorOffset() >= 0) {
    sticky.classList.remove('is-sticky');
    state = false;
  }
};

window.addEventListener('scroll', updateSticky);
window.addEventListener('resize', updateSticky);

updateSticky();
.main-wrapper {
  margin: 48px 48px 0 48px;
  max-width: 80%;
}

.wrapper {
  width: 100%;
  display: flex;
  justify-content: space-between;
  position: relative;
}

.content {
  flex: 0 1 80%;
  width: calc(80% - 24px);
  min-width: 1%;
  margin-right: 24px;
  height: 1200px;
  background-color: #e6e9f0;
}

.nav-container {
  flex-grow: 1;
  width: 20%;
  min-width: 200px;
  position: relative;
  display: block;
}

.nav-menu {
  color: white;
  width: 100%;
  min-width: inherit;
  height: 300px;
  background-color: #04246a;
}

.is-sticky {
  top: 0;
  position: fixed;
  width: calc(20% - 97px);
}
<div class="main-wrapper">
  <div class="wrapper">
    <div class="content">Main content</div>
    <div class="nav-container">
      <div class="nav-menu sticky-element">
        <nav>Side content</nav>
      </div>
    </div>
  </div>
</div>
Techuila
  • 1,237
  • 8
  • 12
0

var sticky = document.getElementsByClassName("sticky-element")[0];
var stickyAnchor = sticky.parentNode;
var state = false;

function getAnchorOffset() {
    return stickyAnchor.getBoundingClientRect().top;
}

updateSticky = function (e) {
    if (!state && (getAnchorOffset() < 0)) {
      sticky.classList.add("is-sticky");
      state = true;
    } else if (state && (getAnchorOffset() >=0 )) {
      sticky.classList.remove("is-sticky");
      state = false;
    }
}

window.addEventListener('scroll', updateSticky);
window.addEventListener('resize', updateSticky);

updateSticky();
.main-wrapper {
    margin: 48px 48px 0 48px;
    max-width: 80%;
}

.wrapper {
    width: 100%;
    display: flex;
    justify-content: space-between;
    position: relative;
}

.content {
    flex: 0 1 80%;
    width: calc(80% - 24px);
    min-width: 1%;
    margin-right: 24px;
    height: 1200px;
    background-color: #e6e9f0;
}

.nav-menu {
    position: static;
    flex: 0 1 20%;
    width: 20%;
    min-width: 20%;
    color: white;
    height: 300px;
    background-color: #04246a;
}

.is-sticky {
    top: 0;
    right:5%;
    position: fixed;
}
<div class="main-wrapper">
  <div class="wrapper">
    <div class="content">
      Main content
    </div>
    <div class="nav-menu sticky-element">
      <nav>
        Side content
      </nav>
    </div>
  </div>
</div>
Why u do dis
  • 418
  • 4
  • 15
  • play around with the right % on the .is-sticky until it fits your needs, Also like i mentioned above, change width to be px on the .content class instead of % – Why u do dis Apr 02 '21 at 11:20
  • Thanks, but the right % isn't really working if the viewport is wide the side nav goes to the screen marges – Renaud is Not Bill Gates Apr 02 '21 at 13:54
  • Can you check my second try please, the problem is with calculating the `right` for the side div if you resize the window you can notice that, but I want the side div to be always in the same vertical position even when I resize the window. – Renaud is Not Bill Gates Apr 02 '21 at 14:14
  • Have a look at my solution @RenaudisNotBillGates – Techuila Apr 06 '21 at 02:24