Home > Back-end >  Stick element inside absolute positioned container
Stick element inside absolute positioned container

Time:08-27

Considering an element ".sticky-element" (orange) that is inside an absolute positioned container ".tab" (green, blue, fuchsia).

I wish to make it "sticky", so when the the parent ".container" (grey) scrolls, the ".sticky-element" stays always on the top.

I've tried without success getting the offset position of the sticky elements and control the "top" accordingly with the scroll position of the container. Is there any pure CSS solution? If not, how to accomplish this with JS?


Here it is a scroll0

scroll1

scroll2

CodePudding user response:

Not 100% if I got what you're looking for, but the orange headers stick to the top when scrolling. I had to move them outside of the containers you had them in so they would display like your photo and added a min-width and height to your sticky class. And finally, set a z-index value on the sticky element.

body {
  padding: 0;
  margin: 0;
}

.wrap {
  height: 100vh;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

.container {
  width: 200px;
  overflow-y: scroll;
  display: flex;
  flex-direction: column;
  row-gap: 50px;
  scroll-snap-type: y mandatory;
}

.group {
  display: flex;
  position: relative;
}

.tab {
  width: 20px;
  height: 100%;
  background: red;
  opacity: 0.9;
  position: absolute;
  overflow: hidden;
  transition: 0.5s width;
}

.tab:hover {
  width: 100%;
}

.sticky-element {
  width: 50px;
  height: 50px;
  min-width: 50px;
  min-height: 50px;
  left: 20px;
  top: 20px;
  background: orange;
  position: sticky;
  z-index:1;
}

.child-handler {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  row-gap: 20px;
}

.child {
  height: 200px;
  scroll-snap-align: start;
}

.group[groupid="1"] .child {
  background: green;
}

.group[groupid="2"] .child {
  background: blue;
}
<body>
  <div >
    <div >
    
      <div >Sticky 1</div>
      
      <div  groupid="1">
        <div >
          
        </div>
        <div >
          <div ></div>
          <div ></div>
          <div ></div>
          <div ></div>
          <div ></div>
        </div>
      </div>
      
      <div >More Sticky</div>
      
      <div  groupid="2">
        <div >
          
        </div>
        <div >
          <div ></div>
          <div ></div>
          <div ></div>
          <div ></div>
          <div ></div>
        </div>
      </div>
    </div>
  </div>
</body>

CodePudding user response:

Based on the solution of @Phaelax z I solve the problem with this approach:

$.each($(".group"), function() {
  $(this).css("min-height", $(this).find(".child-handler").innerHeight());
});

function animate(el, width) {
  el.stop().animate({
    width: width
  }, {
    duration: 500,
    step: function(currentWidth) {
      const sticky = el.closest(".group").children(".sticky-element");
      const left = parseInt(sticky.css("left"));
      sticky.css("width", currentWidth - left);
    }
  });
}
$(".tab")
  .mouseenter(function() {
    animate($(this), "100%");
  })
  .mouseleave(function() {
    animate($(this), 20);
  });
body {
  padding: 0;
  margin: 0;
}

.wrap {
  height: 100vh;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

.container {
  width: 200px;
  overflow-y: scroll;
  display: flex;
  flex-direction: column;
  row-gap: 50px;
  scroll-snap-type: y mandatory;
}

.group {
  display: flex;
  position: relative;
}

.sticky-element {
  max-width: 50px;
  height: 50px;
  width: 0;
  left: 20px;
  top: 20px;
  margin-top: 20px;
  margin-bottom: 20px;
  background: orange;
  position: sticky;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}

.tab-child-wrap {
  position: absolute;
  width: 100%;
  height: 100%;
}

.tab {
  width: 20px;
  height: 100%;
  background: red;
  opacity: 0.9;
  position: absolute;
  overflow: hidden;
  z-index: 1;
}

.tab-content {
  width: 100%;
}

.child-handler {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  row-gap: 20px;
}

.child {
  height: 200px;
  scroll-snap-align: start;
}

.group[groupid="1"] .child {
  background: green;
}

.group[groupid="2"] .child {
  background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<body>
  <div >
    <div >
      <div  groupid="1">
        <div >Sticky 1</div>
        <div >
          <div >
            <div >Content</div>
          </div>
          <div >
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
          </div>
        </div>
      </div>
      <div  groupid="2">
        <div >More Sticky</div>
        <div >
          <div >
            <div >Content</div>
          </div>
          <div >
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
            <div ></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

  • Related