skip to Main Content

How can an element be defined to behave like a sticky element only when the remaining height of the element is greater than a specific size (that I will call sticky container margin)?

For example, in the below image:
image describing the case below

You can see that the light blue container has a sticky red element, and the sticky container margin is showed as a dark blue line. When the container element is leaving the screen, the red element stays sticky until the sticky container margin reaches the end of the container.

Here is an initial code to try out some solutions. I tried to make the blue line a container, but that messes up the initial position of the rest of the content.

section {
  height: 300lvh;
}

.content {
  background: #eee;
  height: 80lvh;
}

.box {
  height: 120lvh;
  background: #9f9;
  display: flex;
  flex-direction: column;
}

.sticky {
  position: sticky;
  top: 0px;
  height: 20lvh;
  background: #99f;
}

.end {
  color: red;
  padding-top: 50px;
}

.flex-end {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
<section>
  <div class="content">Prev content</div>
  <div class="box">
    <div class="sticky">
      Sticky element
    </div>
    <div>
      Content
    </div>
    <div class="flex-end">
      Content
    </div>
  </div>
  <div class="content end">
    When this is visible, the sticky element should go up
  </div>
</section>

2

Answers


  1. One solution is to use a wrapper for the sticky content. The concept is to have a smaller container to start being scrolled out of view when content end comes in.

    You don’t need Javascript if the height of the sticky element is hard-coded (20lvh in your case), or else you will need to use Javascript to get the height of the sticky element.

    .box {
      --sticky-height: 20lvh;
      height: 120lvh;
      background: #9f9;
      position: relative;
    }
    
    .sticky-wrapper {
      position: absolute;
      width: 100%;
      height: calc(100% - 100lvh + var(--sticky-height));
      z-index: 1;
    }
    
    .content-container {
      position: relative;
      top: var(--sticky-height);
      height: calc(100% - var(--sticky-height));
      /*The css for laying out the contents originally in box needs to be moved here*/
      display: flex;
      flex-direction: column;
      justify-content: space-between;
    }
    

    As shown in below example:

    section {
      height: 300lvh;
    }
    
    .content {
      background: #eee;
      height: 80lvh;
    }
    
    .box {
      --sticky-height: 20lvh;
    
      height: 120lvh;
      background: #9f9;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      position: relative;
    }
    
    .sticky {
      position: sticky;
      top: 0px;
      height: var(--sticky-height);
      background: #99f;
    }
    
    .end {
      color: red;
      padding-top: 50px;
    }
    
    .flex-end {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
    }
    
    .sticky-wrapper {
      position: absolute;
      width: 100%;
      height: calc(100% - 100lvh + var(--sticky-height));
      z-index: 1;
    }
    
    .content-container {
      position: relative;
      top: var(--sticky-height);
      height: calc(100% - var(--sticky-height));
      display: flex;
      flex-direction: column;
      justify-content: space-between;
    }
    <section>
      <div class="content">Prev content</div>
      <div class="box">
        <div class="sticky-wrapper">
          <div class="sticky">
            Sticky element
          </div>
        </div>
        <div class="content-container">
          content
          <div class="flex-end">
            Content
          </div>
        </div>
      </div>
      <div class="content end">
        When this is visible, the sticky element should go up
      </div>
    </section>
    Login or Signup to reply.
  2. I would play with some margin

    section {
      height: 300lvh;
    }
    
    .content {
      background: #eee;
      height: 80lvh;
    }
    
    .box {
      height: 120lvh;
      background: #9f9;
      display: flex;
      flex-direction: column;
    }
    
    .sticky {
      position: sticky;
      top: 0px;
      height: 20lvh;
      margin-bottom: 80lvh; /* here */
      background: #99f;
    }
    
    .sticky + * {
      margin-top: -80lvh; /* and here */
    }
    
    .end {
      color: red;
      padding-top: 50px;
    }
    
    .flex-end {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
    }
    <section>
      <div class="content">Prev content</div>
      <div class="box">
        <div class="sticky">
          Sticky element
        </div>
        <div>
          Content
        </div>
        <div class="flex-end">
          Content
        </div>
      </div>
      <div class="content end">
        When this is visible, the sticky element should go up
      </div>
    </section>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search