Home > front end >  Why div elements overlap when position is set to sticky? How to prevent it?
Why div elements overlap when position is set to sticky? How to prevent it?

Time:07-09

I've created a sidebar, where I have three container elements. I want them to be sticky as the user scrolls through the page and when the user reaches the footer I want these elements to behave like normal elements and not overlap with each other.

Here is the code representing the problem. How to resolve this overlapping issue?

<div >
  <div >
    <div >
      <p>I would hold all the subscription form elements</p>
    </div>
  </div>
  <div >
    <div >
      <p>
      I would contain all the social buttons
      </p>
    </div>
  </div>
  <div >
    <div >
    <p>
    Here is the sidebar banners
    </p>
    </div>
  </div>
</div>
.sidebar-subscription-form-container {
  top: 0px;
  height: 30px;
  z-index:1;
  position: sticky;
}

.social-buttons-container {
  top: 400px;
  height:30px;
  z-index:1;
  position: sticky;
}

.sidebar-banner-container {
  top: 800px;
  height:30px;
  z-index:1;
  position: sticky;
}

https://jsfiddle.net/nirmalkumar1997/L0yd5hq1/84/

CodePudding user response:

Since you have hardcoded the height values of each element, why not simply offset the top property in each element by the height value times the number of elements down it is:

.sidebar-subscription-form-container {
  top: 0px;
  height: 30px;
  z-index: 1;
  position: sticky;
}

.social-buttons-container {
  top: 400px;
  height: 30px;
  z-index: 1;
  position: sticky;
  top: 30px;
}

.sidebar-banner-container {
  top: 800px;
  height: 30px;
  z-index: 1;
  position: sticky;
  top: 60px;
}
<div >
  <div >
    <div >
      <p>I would hold all the subscription form elements</p>
    </div>
  </div>
  <div >
    <div >
      <p>
        I would contain all the social buttons
      </p>
    </div>
  </div>
  <div >
    <div >
      <p>
        Here is the sidebar banners
      </p>
    </div>
  </div>
</div>

I added 30px for the second element, and 60px for the 3rd element.

To make this more dynamic, you could use a CSS custom property to keep everything in sync if you make changes to height, and run a calc on the element offset * height.

::root {
  --container-height: 30px
}

.sidebar-subscription-form-container {
  top: calc(var(--container-height) * 0);
  height: var(--container-height);
  z-index: 1;
  position: sticky;
}

.social-buttons-container {
  top: 400px;
  height: var(--container-height);
  z-index: 1;
  position: sticky;
  top: calc(var(--container-height) * 1);
}

.sidebar-banner-container {
  top: 800px;
  height: var(--container-height);
  z-index: 1;
  position: sticky;
  top: calc(var(--container-height) * 2);
}
<div >
  <div >
    <div >
      <p>I would hold all the subscription form elements</p>
    </div>
  </div>
  <div >
    <div >
      <p>
        I would contain all the social buttons
      </p>
    </div>
  </div>
  <div >
    <div >
      <p>
        Here is the sidebar banners
      </p>
    </div>
  </div>
</div>

CodePudding user response:

The problem with your code is the height of section class. As the nearest block-ancestor to all the three containers is section, they will stick as soon as they hit the edge of the section class.

According to Mozilla Documentation

A stickily positioned element is an element whose computed position value is sticky. It's treated as relatively positioned until its containing block crosses a specified threshold (such as setting top to value other than auto) within its flow root (or the container it scrolls within), at which point it is treated as "stuck" until meeting the opposite edge of its containing block.

You can find the entire info here - Link

For achieving sticky behavior and removing overlapping of containers, you can try to increase the height of section class. For example -

.section {
    height: 4000px; // Needs greater value as top is 400px and 800px for children elements.
}
  • Related