How to create a buttery-smooth loading hero experience with GSAP in Elementor Hosting

SHARE

SIGN UP FOR THE NEWSLETTER

Your subscription could not be saved. Please try again.
Your subscription has been successful.


Code:

Javascript/GSAP

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.3/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.3/Flip.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/CustomEase.min.js"></script>
<script>
    document.addEventListener("DOMContentLoaded", () => {
  gsap.registerPlugin(CustomEase);
  CustomEase.create(
    "hop",
    "M0,0 C0.29,0 0.348,0.05 0.422,0.134 0.494,0.217 0.484,0.355 0.5,0.5 0.518,0.662 0.515,0.793 0.596,0.876 0.701,0.983 0.72,0.987 1,1 "
  );

  function splitTextIntoSpans(selector) {
    let elements = document.querySelectorAll(selector);
    elements.forEach((element) => {
      let text = element.innerText;
      let splitText = text
        .split("")
        .map(function (char) {
          return `<span>${char === " " ? "  " : char}</span>`;
        })
        .join("");
      element.innerHTML = splitText;
    });
  }
  splitTextIntoSpans(".header h1");

  function animateCounter() {
    const counterElement = document.querySelector(".counter p");
    let currentValue = 0;
    const updateInterval = 300;
    const maxDuration = 2000;
    const endValue = 100;
    const startTime = Date.now();

    const updateCounter = () => {
      const elapsedTime = Date.now() - startTime;
      if (elapsedTime < maxDuration) {
        currentValue = Math.min(
          currentValue + Math.floor(Math.random() * 30) + 5,
          endValue
        );
        counterElement.textContent = currentValue;
        setTimeout(updateCounter, updateInterval);
      } else {
        counterElement.textContent = endValue;
        setTimeout(() => {
          gsap.to(counterElement, {
            y: -20,
            duration: 1,
            ease: "power3.inOut",
            onStart: () => {
              revealLandingPage();
            },
          });
        }, -500);
      }
    };

    updateCounter();
  }

  gsap.to(".counter p", {
    y: 0,
    duration: 1,
    ease: "power3.out",
    delay: 1,
    onComplete: () => {
      animateCounter();
    },
  });

  const revealLandingPage = () => {
    gsap.to(".hero", {
      clipPath: "polygon(0% 100%, 100% 100%, 100% 0%, 0% 0%)",
      duration: 2,
      ease: "hop",
      onStart: () => {
        gsap.to(".hero", {
          transform: "translate(-50%, -50%) scale(1)",
          duration: 2.25,
          ease: "power3.inOut",
          delay: 0.25,
        });

        gsap.to(".overlay", {
          clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)",
          duration: 2,
          delay: 0.5,
          ease: "hop",
        });

        gsap.to(".hero-img img", {
          transform: "scale(1)",
          duration: 2.25,
          ease: "power3.inOut",
          delay: 0.25,
        });

        gsap.to(".header h1 span", {
          y: 0,
          stagger: 0.1,
          duration: 2,
          ease: "power4.inOut",
          delay: 0.75,
        });
      },
    });
  };
});

</script>

CSS

<style>
.counter {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 40px;
  height: 20px;
  text-align: center;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
  z-index: 0;
}

.counter p {
  position: relative;
  display: block;
  transform: translateY(20px);
}

.hero {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.7);
  width: 100vw;
  height: 100vh;
  clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
  will-change: transform;
  z-index: 1;
}

.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #F6520C;
  clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);
  z-index: 2;
}

.header {
  position: absolute;
  width: 100%;
  height: 20vh;
  left: 0;
  clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);
  z-index: 1;
}

.header h1 {
  font-weight: lighter;
  text-align: center;
  margin: 0;
  padding: 0;
  line-height: 100%;
}

.header h1 span {
  position: relative;
  display: inline-block;
  transform: translateY(500px);
}

.hero-img {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 80vh;
  overflow: hidden;
  z-index: 0;
}

.hero-img img {
  transform: scale(2);
}

</style>



Video:

SIGN UP FOR THE NEWSLETTER

Your subscription could not be saved. Please try again.
Your subscription has been successful.