Home > Software design >  CSS: How to don't reset onhover animation on every hover
CSS: How to don't reset onhover animation on every hover

Time:12-29

I have simple on hover CSS animation which makes slide transition between images.

When the user makes the hover on SECTION ONE and before the animation ends make hover on SECTION two, animation restart and make lagging move.

MY CODE:

var $circle = $('#circle');

function moveCircle(e) {
    TweenLite.to($circle, 0.8, {
    css: {
      left: e.pageX,
      top: e.pageY
    }
  });
}

$(window).on('mousemove', moveCircle);
@import "compass/css3";

@keyframes in {
    from {
        transform: translateY(-100%);
    }
    to {
        transform: translateY(0);
    }
}
@keyframes out {
    from {
        transform: translateY(0);
    }
    to {
       transform: translateY(100%);
    }
}

html {
  background: #0E3741;
}

#circle {
  position: absolute;
  pointer-events : none;
  width: 400px;
  height: 200px;
  top: 50%;
  left: 50%;
  margin: -50px 0 0 -50px;
}

#circle .circle-wrapper {
    overflow: hidden;
    width: 400px;
    height: 200px;
    position: relative;
  }
  
#circle img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 400px;
    height: 200px;
    object-fit: cover;
    overflow: hidden;
  }

#wrapper {
  display: flex;
  flex-direction: column;
}

.special-element {
  width: 100%;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}

#one {
  background: blue;
}

#two {
  background: red;
}

#one:hover ~ #circle .circle-wrapper #imgOne {
  animation: in 1s ease-in-out;
  z-index: 2;
}

#one:hover ~ #circle .circle-wrapper #imgTwo {
  animation: out 1s ease-in-out;
}

#two:hover ~ #circle .circle-wrapper #imgTwo {
  animation: in 1s ease-in-out;
  z-index: 2;
}

#two:hover ~ #circle .circle-wrapper #imgOne {
  animation: out 1s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.4/TweenMax.min.js"></script>

<section id="wrapper">
  <section  id="one">
    section one
  </section>

  <section  id="two">
    section two
  </section>
  
  <div id="circle">
    <div >
      <img id="imgOne" src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
    <img id="imgTwo" src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
    </div>
  </div>
</section>

Is there any solution how I can prevent this lagging issue?

Maybe is there any solution to how I can solve it and make this animation smooth?

I'm looking for something like animation on this website.

CodePudding user response:

I think that problem is because "moving circle function". Moving dom element with Left and right is not good for performance. You should move the circle with "transform". transform runs with GPU acceleration and it performs better and make move smooth.

Try this code.

function moveCircle(e) {
    TweenLite.to($circle, 0.8, {
    css: {
      transform: `translate(${e.pageX}px, ${e.pageY}px)`
    }
  });
}

CodePudding user response:

I have been playing around a little bit with the gsap library today. I've honestly never done anything with or like it. Tried to do it with the x and y params that you may pass to gsap. It will take care of the transformations - also the TimeLine stuff is quite handy.

The result is not that great, also the animations look like it could be done better, but maybe it might still help you out. You could also improve some of the logic and animation probably. At least it runs quite stable - performance wise.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/reset.min.css" />
  <script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
  <script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/CSSPlugin.min.js"></script>
  <style type="text/css">
    .section {
      display: block;
      width: 100%;
      height: 200px;
      border-bottom: 1px solid red;
    }
    
    .overlay {
      position: absolute;
      top: 0;
      left: 0;
      display: none;
      border: none; // 1px dashed black;
      background: transparent; // lavender;
      overflow: hidden;
    }
    
    .stack {
      position: relative;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      min-width: 300px;
      min-height: 300px;
      width: 480px;
      height: 320px;
      z-index: 0;
    }
    
    .anim-img {
      position: absolute;
      top: 0;
      left: 0;
      width: auto;
      height: auto;
      max-width: 100%;
      object-fit: contain;
      z-index: 1;
    }
  </style>
</head>

<body>
  <main >
    <section >section 1</section>
    <section >section 2</section>
    <div >
      <div >
        <img id="img-1"  src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
        <img id="img-2"  src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
      </div>
    </div>
  </main>

  <script type="application/javascript">
    window.onload = () => {
      const overlay = document.querySelector(".overlay");
      const img1 = document.getElementById("img-1");
      const img2 = document.getElementById("img-2");
      const s1 = document.querySelector(".section-1");
      const s2 = document.querySelector(".section-2");
      const main = document.querySelector(".main");

      let anim;

      let isS1active = false;
      let isS2active = false;

      let showEl;
      let hideEl;

      let leaveTimeout;

      function reverseFadeInOut(showEl, hideEl) {
        console.log("create reverse timeline anim -> ", {
          showEl,
          hideEl
        });
        const tl = gsap.timeline({
          paused: true
        });
        tl
          .to(showEl, {
            zIndex: 1
          }, 0)
          .to(hideEl, {
            zIndex: 10
          }, 0)
          .to(hideEl, {
            y: "-100%",
            duration: 0.375
          }, 0)
          .to(hideEl, {
            display: "none"
          }, 0.375)
          .to(hideEl, {
            zIndex: 1
          }, 0.375)
          .to(showEl, {
            display: "block",
            zIndex: 10
          }, 0.375)
          .fromTo(showEl, {
            y: "-100%"
          }, {
            y: 0,
            duration: .375
          }, 0.375)
          .to(hideEl, {
            display: "none"
          });
        return tl;
      }

      function fadeInOut(showEl, hideEl) {
        console.log("create timeline anim -> ", {
          showEl,
          hideEl
        });
        const tl = gsap.timeline({
          paused: true
        });
        tl
          .to(hideEl, {
            zIndex: 1
          }, 0)
          .to(showEl, {
            display: "block",
            zIndex: 10
          }, 0)
          .fromTo(showEl, {
            y: "-100%"
          }, {
            y: 0,
            duration: .75
          }, 0)
          .fromTo(hideEl, {
            y: 0
          }, {
            y: "-100%",
            duration: .75
          }, 0)
          .to(hideEl, {
            display: "none"
          }, 0.75);
        return tl;
      }

      function animateImage() {
        if (isS1active || isS2active) {
          if (isS1active) {
            showEl = img1;
            hideEl = img2;
          } else if (isS2active) {
            showEl = img2;
            hideEl = img1;
          }

          if (!anim) {
            console.log("create new animation");
            anim = fadeInOut(showEl, hideEl);
            anim.play();
          } else {
            console.log("anim active:", anim.isActive());
            if (anim.isActive()) {
              console.log("reverse");
              anim.kill();
              anim = reverseFadeInOut(showEl, hideEl);
              anim.play();
            } else {
              anim = fadeInOut(showEl, hideEl);
              anim.play();
            }
          }
        }
      }

      function moveOverlay(e) {
        e.preventDefault();
        e.stopPropagation();
        gsap.set(overlay, {
          x: e.pageX   15,
          y: e.pageY   15,
          display: isS1active || isS2active ? "block" : "none"
        });
      }

      function mouseOver(e, el, isEntering) {
        e.preventDefault();
        e.stopPropagation();
        el.classList.toggle("active");
        isS1active = s1.classList.contains("active");
        isS2active = s2.classList.contains("active");
        if (isEntering) {
          clearTimeout(leaveTimeout);
          animateImage();
        } else {
          leaveTimeout = setTimeout(() => {
            if (anim) {
              console.log("kill anim");
              anim.kill();
              anim = null;
            }
            gsap.timeline({
              onComplete: () => {
                console.log("clear props");
                gsap.set(".anim-img", {
                  clearProps: true
                });
              }
            });
          }, 500);
        }
      }

      gsap.set(overlay, {
        x: "0",
        y: "0"
      });
      gsap.set(img1, {
        x: "0",
        y: "-100%"
      });
      gsap.set(img2, {
        x: "0",
        y: "-100%"
      });
      window.addEventListener("mousemove", moveOverlay);
      s1.addEventListener("mouseenter", (e) => {
        mouseOver(e, s1, true);
      });
      s1.addEventListener("mouseleave", (e) => {
        mouseOver(e, s1, false);
      });
      s2.addEventListener("mouseenter", (e) => {
        mouseOver(e, s2, true);
      });
      s2.addEventListener("mouseleave", (e) => {
        mouseOver(e, s2, false);
      });
    }
  </script>
</body>

</html>

  • Related