JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.0/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.0/gsap.min.js"></script>
<div style="height: 60vh">
Some content
</div>
<div class="panels-wrapper">
<div class="panel" style="background: teal"></div>
<div class="panel" style="background: lightgreen"></div>
<div class="panel" style="background: pink"></div>
</div>
<div style="height: 60vh">
Some content
</div>
CSS
.panel{border-radius: 60px; --height: 400px; height: var(--height); position: relative;}
JavaScript
gsap.registerPlugin(ScrollTrigger);
const panels = document.querySelectorAll('.panel:not(:first-child)');
const bottom = 40;
gsap.set('.panel:not(:last-child)', {
marginBottom: (i, e) => -e.offsetHeight + bottom + 'px',
zIndex: (i) => panels.length - i
});
panels.forEach((element, i) => {
ScrollTrigger.create({
trigger: element,
pin: true,
start: 'bottom bottom-=' + (bottom * (panels.length - i - 1)) + 'px',
end: '+=' + ((element.offsetHeight - bottom) * (i + 1)),
scrub: true,
pinSpacing: i + 1 === panels.length ? true : false
});
});