Search code examples
htmlcsssticky

Nested sticky element with zero left does not sticky


Why my nested sticky element with left: 0 does not stick while the nested element with top: 0 sticks normally?

.scroll {
  width: 200px;
  height: 200px;
  border: 1px solid;
  overflow: auto;
}

.container {
  width: 600px;
  height: 1000px;
}

.sticky-left {
  position: sticky;
  left: 0;
}

.sticky-top {
  position: sticky;
  top: 0;
}
<div class="scroll">
  <div class="sticky-top">sticky-top</div>
  <div class="sticky-left">sticky-left</div>
  <div class="container">
    <div class="sticky-top">sticky-top-nested</div>
    <div class="sticky-left">sticky-left-nested</div>
  </div>
</div>


Solution

  • Let's add some border and we will clearly see what is happening:

    .scroll {
      width: 200px;
      height: 200px;
      border: 1px solid;
      overflow: auto;
    }
    .scroll > div {
      border:2px solid green;
    }
    
    .container {
      width: 600px;
      height: 1000px;
      border:2px solid red!important;
    }
    .container > div {
      border:2px solid green;
    }
    
    .sticky-left {
      position: sticky;
      left: 0;
    }
    
    .sticky-top {
      position: sticky;
      top: 0;
    }
    <div class="scroll">
      <div class="sticky-top">sticky-top</div>
      <div class="sticky-left">sticky-left</div>
      <div class="container">
        <div class="sticky-top">sticky-top-nested</div>
        <div class="sticky-left">sticky-left-nested</div>
      </div>
    </div>

    As you can see, the nested sticky elements are both having their width equal to parent width (since they are block element) so there is no room for the left-sticky to have any sticky behavior1 since it has width:100% unlike the top one that can still stick because its height is less that the parent height.

    For the non-nested elements I think it's clear.


    Make the element inline-block or reduce the width and you will have a sticky behavior:

    .scroll {
      width: 200px;
      height: 200px;
      border: 1px solid;
      overflow: auto;
    }
    .scroll > div {
      border:2px solid green;
    }
    
    .container {
      width: 600px;
      height: 1000px;
      border:2px solid red!important;
    }
    .container > div {
      border:2px solid green;
      width:150px;
    }
    
    .sticky-left {
      position: sticky;
      left: 0;
    }
    
    .sticky-top {
      position: sticky;
      top: 0;
    }
    <div class="scroll">
      <div class="sticky-top">sticky-top</div>
      <div class="sticky-left">sticky-left</div>
      <div class="container">
        <div class="sticky-top">sticky-top-nested</div>
        <div class="sticky-left">sticky-left-nested</div>
      </div>
    </div>


    1 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.ref

    In your case you were always meeting the opposite edge.