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?
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>