JSFiddle - React, Tailwind, and code Playground

by davidxmartins

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollTrigger.min.js"></script>

<div class="container">
    <section class="w-1">
        <h1>Text</h1>
    </section>
    <section class="w-2 pink">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 grey">
        <h1>Text</h1>
    </section>
    <section class="w-1 violet">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 pink">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 grey">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-1 violet">
        <h1>Text</h1>
    </section>
    <section class="w-2 pink">
        <h1>Text</h1>
    </section>
    <section class="w-2 grey">
        <h1>Text</h1>
    </section>
    <section class="w-1 violet">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 pink">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 grey">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-1 violet">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-2 pink">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
        </div>
    </section>
    <section class="w-1">
        <div>
            <h1>Heading</h1>
            <p>Paragraph after heading</p>
       ...

CSS

body {
    margin: 0;
    padding: 0;
}

.container {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-wrap: nowrap;
    background-color: red;
      overflow-x: scroll;
  overflow-y: hidden;
    position: absolute;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
::-webkit-scrollbar {
  display: none;
}

h1 {
    color: #fff;
    text-align: center;
    text-transform: uppercase;
}

p {
    color: #fff;
    text-align: center;
}

section {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    aling-content: center;
    justify-content: center;
}

.w-1 {
    height: 100vh;
    flex: 0 0 100vw;
    background-color: blue;
}

.w-2 {
    height: 100vh;
    flex: 0 0 100vw;
}

.violet {
    background-color: violet;
}

.pink {
    background-color: pink;
}

.grey {
    background-color: grey;
}

JavaScript

gsap.registerPlugin(ScrollTrigger);

let sections = gsap.utils.toArray("section");
let container = document.querySelector(".container");
let elements = gsap.utils.toArray(document.querySelectorAll("section > *"));

let timeline = gsap.timeline();

timeline.to(sections, {
    x: () =>
        -(container.scrollWidth - document.documentElement.clientWidth) + "px",
    ease: "none",
    scrollTrigger: {
        pin: true,
        scrub: 1,
        overwrite: "auto",
        trigger: container,
        end: () => container.scrollWidth - document.documentElement.clientWidth
    }
});

let scrollTriggerTimeline = gsap.timeline();

elements.forEach((element) => {
    scrollTriggerTimeline.from(element, {
        yPercent: 300,
        opacity: 0,
        overwrite: "auto",
        scrollTrigger: {
            scrub: 1,
            start: () => element.parentNode.offsetLeft - window.innerWidth,
            end: () =>
                element.parentNode.offsetLeft -
                window.innerWidth +
                element.parentNode.getBoundingClientRect().width
        }
    });
});

elements.forEach((element) => {
    scrollTriggerTimeline.to(element, {
        yPercent: 300,
        opacity: 0,
        overwrite: "auto",
        scrollTrigger: {
            scrub: 1,
            immediateRender: false,
            start: () =>
                element.parentNode.offsetLeft -
                element.parentNode.getBoundingClientRect().width / 2,
            end: () =>
                element.parentNode.offsetLeft +
                element.parentNode.getBoundingClientRect().width
        }
    });
});