<figure class="img-container">
  <img src="https://images.unsplash.com/photo-1594903057066-3c2abea0f9cf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=600&q=60" alt="overlay-image">
</figure>
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  padding: 0 40px;
  visibility: hidden;
}

.img-container {
  position: relative;
  overflow: hidden;
  img {
    width: 100%;
    // position: absolute;
    opacity: 0;
  }
  
  &:after {
    content: "";
    position: absolute;
    width: 0%;
    height: 100%;
    top: 0;
    left: 0;
    background: #000000;
  }
}
View Compiled
const tl = gsap.timeline();

const rule = CSSRulePlugin.getRule(".img-container:after");

tl.to("body", { duration: 0.5, autoAlpha: 1 })
  .to(rule, { duration: 1, width: "100%", ease: "Power2.ease" })
  .set(rule, { duration: 0, right: 0, left: "unset" })
  .to(rule, { duration: 1, width: "0%", ease: "Power2.ease" })
  .to("img", { duration: 0.2, opacity: 1, delay: -1 })
  .from(".img-container img", {
    duration: 1,
    scale: 1.4,
    ease: "Power2.easeInOut",
    delay: -1.2
  });

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/CSSRulePlugin.min.js