Search code examples
reactjsgsapclip-path

Button doesn't disappear immediately; need to move mouse during animation using clip-path


I am setting the clipPath property from circle(0%) to circle(100%) using GSAP timeline.

let t1 = useRef();
useEffect(() => {
    t1.current = gsap.timeline({
      defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
    });
    t1.current.paused(true); //to ensure animation doesn't play immediately
    t1.current.to(".overlay", { clipPath: "circle(100%)" });
  });

  const handleClick = () => {
    t1.current.play(); //start the animation
  };

  const handleClose = () => {
    t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
  };

GSAP Animation

Complete React Component code:

import React, { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faWindowClose } from "@fortawesome/free-solid-svg-icons";

export default function GSAPFullScreen() {
  let t1 = useRef();
  useEffect(() => {
    t1.current = gsap.timeline({
      defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
    });
    t1.current.paused(true); //to ensure animation doesn't play immediately
    t1.current.to(".overlay", { clipPath: "circle(100%)" });
  }, []);

  const handleClick = () => {
    t1.current.play(); //start the animation
  };

  const handleClose = () => {
    t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
  };
  return (
    <>
      <div
        className="overlay"
        style={{
          clipPath: "circle(0%)",
          width: "100%",
          height: "100%",
          position: "fixed",
          overflowY: "scroll",
          overflowX: "hidden",
          backgroundColor: "purple",
        }}
      >
        <FontAwesomeIcon
          icon={faWindowClose}
          size="2x"
          style={{
            position: "absolute",
            top: "2rem",
            right: "2rem",
            color: "white",
            cursor: "pointer",
          }}
          onClick={handleClose}
        />
        <div className="container md" style={{ color: "white" }}>
          <br /> 
          <div style={{ fontWeight: "bold" }}>This is an amazing Question</div>
          <div>What is your question? Can you guess?</div>
          <div>Option 1</div>
          <div>Option 2</div>
          <div>Option 3</div>
          <div>Option 4</div>
        </div>
      </div>
      <div className="container" style={{ height: "100vh" }}>
        <div className="flex">
          <button className="lg p-1 btn" onClick={() => handleClick()}>
            Launch Animation
          </button>
        </div>
      </div>
    </>
  );
}

Relevant CSS:

   .container {
      max-width: 1100px; /* Ensures heading is in center beyond 1100px*/
      margin: 0 auto; /* Ensures to keep the 1100px container in middle of the screen; 
                           until 1100px it will be on the side and this property will not have any affect*/
    
      overflow: auto; /* This removes the space on the top of the heading which was created because of margin: 10px 0 on h1*/
      padding: 0 40px;
    }

.btn {
  display: inline-block;
  padding: 10px 30px;
  cursor: pointer;
  background: var(--primary-color);
  color: #fff;
  border: none;
  border-radius: 5px;
}
.md {
  font-size: 2rem;
}
.lg {
  font-size: 3rem;
}

.flex {
  display: flex;
  justify-content: center; /* aligns along the main axis*/
  align-items: center;
  height: 100%;
}

.p-1 {
  padding: 1rem; /*1 rem is usually 16px depending the size at root*/
}
.btn:hover:enabled{
transform: scale(0.98); /*reduces the size of button a bit*/
}

Solution

  • When the button has the pseudo class :hover a transform will be applied to the element, which means that it the stacking context is changed (see also Stacking without the z-index property).

    To fix this you can add z-index: 1 to the overlay class or remove the transform from the :hover class (Not ideal).