JSFiddle - React, Tailwind, and code Playground

by Torwan

HTML

<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js"></script>
<section class="paralax">
  <div class="bg"></div>
  <h1 id="txt">Simple parallax sections</h1>
</section>
<section>
  <h1>Hey look, a title</h1>
</section>
<section>
  <h1>They just keep coming</h1>
</section>
<section>
  <h1>So smooth though</h1>
</section>
<section>
  <h1>Nice, right?</h1>
</section>

CSS

section {
  position: relative;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.bg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  /*background-image: url("https://creativium.eu/lilmedia/head_background.jpg");*/
  background-image: url("https://creativium.eu/lilmedia/head_background_prev_for_paralax.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

h1 {
  color: white;
  text-shadow: 1px 1px 3px black;
  z-index: 1;
  font-size: 3em;
  font-weight: 400;
}

JavaScript

gsap.registerPlugin(ScrollTrigger);
let app = document.querySelector('#txt');

let getRatio = el => window.innerHeight / (window.innerHeight + el.offsetHeight);
app.append(window.innerHeight);

gsap.utils.toArray("section").forEach((section, i) => {
  section.bg = section.querySelector(".bg"); 

  gsap.fromTo(section.bg, {
    backgroundPosition: () => i ? `50% ${-window.innerHeight * getRatio(section)}px` : "50% 0px"
  }, {
    backgroundPosition: () => `50% ${window.innerHeight * (1 - getRatio(section))}px`,
    ease: "none",
    scrollTrigger: {
      trigger: section,
      start: () => i ? "top bottom" : "top top", 
      end: "bottom top",
      scrub: true,
      markers: true,
      invalidateOnRefresh: true // to make it responsive
    }
  });

});