Tips for CSS: Preventing onhover animation from resetting with each hover

I've created an on-hover CSS animation that smoothly transitions between images.

However, I encountered a lagging issue when the user quickly hovers over SECTION ONE and SECTION TWO before the animation ends, causing the animation to restart and lag.

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 class="special-element" id="one">
    section one
  </section>

  <section class="special-element" id="two">
    section two
  </section>
  
  <div id="circle">
    <div class="circle-wrapper">
      <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 a way to prevent the lagging issue and make the animation smoother?

Any suggestions on how to improve the animation and achieve a smoother transition like this website?

Answer №1

New and Improved

Using the gsap library, you can achieve a simplified version of the animation. It's recommended to avoid mixing plain CSS with gsap unless you are utilizing CSS within the gsap library itself. GSAP manipulates properties like transformation, so it's advised to use transform over left/top for hardware acceleration.

I've made some enhancements to the previously shared code for a smoother look. Additionally, I've added a slight zoom and horizontal shift effect similar to the animation on the specified website. The animation now initiates from the bottom for a refined appearance.

The animation on the referenced page is exceptionally well-crafted using WebGL. It's not your standard animation and demands significant effort to execute, especially for non-designers. It involves a 3D transformation matrix and various other effects combined.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b392e382e3f662838380b7e657b657a">[email protected]</a>/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: 300px;
      border-bottom: 1px solid red;
    }
    
    .overlay {
      position: absolute;
      top: 0;
      left: 0;
      display: none;
      background: transparent;
      z-index: -1;
    }
    
    .stack {
      position: relative;
      min-width: 300px;
      min-height: 300px;
      width: 480px;
      height: 320px;
      max-width: 480px;
      max-height: 320px;
      overflow: hidden;
      z-index: 1;
    }
    
    .img {
      position: absolute;
      top: 0;
      left: 0;
      width: auto;
      height: auto;
      max-width: 100%;
      object-fit: contain;
      z-index: -1;
    }
  </style>
</head>

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

  <script type="application/javascript">
    // JavaScript code will go here
  </script>
</body>

</html>

Previous Solution

// Old JavaScript code was here

Answer №2

The issue seems to be related to the use of the "moving circle function". Moving a DOM element to the left and right can negatively impact performance. It would be better to utilize the "transform" property to move the circle instead. By using "transform", the operation will be GPU accelerated, resulting in better performance and smoother movement.

You can try implementing the following code:

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

Answer №3

A solution exists to modify the duration of the TweenLite.to function by adjusting the value of the second parameter. The duration parameter can be changed as needed. For more details, refer to the documentation here:

https://i.sstatic.net/RtguO.png

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

function moveCircle(e) {
    TweenLite.to($circle, 0.1, {
    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 class="special-element" id="one">
    section one
  </section>

  <section class="special-element" id="two">
    section two
  </section>

  <div id="circle">
    <div class="circle-wrapper">
      <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>

Answer №4

The webpage employs canvas for its dynamic slideshow and incorporates webgl for the sleek reveal effects.

<div class="site-footer">
 <div class="js-scroll-height"></div>
 <canvas width="780" height="624" class="js-webgl" style="width: 1041px;height: 833px;opacity: 1;border: 1px solid brown;"></canvas>
</div>


To achieve a similar reveal effect, we can utilize basic animation and z-index manipulation:

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

function movecursor(e) {
  TweenLite.to($cursor, 0.8, {
    css: {
      left: e.pageX,
      top: e.pageY
    }
  });
}
$(window).on('mousemove', movecursor);

let topImg = null;
$('.special-element').mouseenter((e) => {
  //make all images at same level
  $('.img-wrapper').css({ zIndex: '1' });

  //make last focused image at second highest level
  if (topImg) topImg.css({ zIndex: '2' });

  //make current image as topImage 
  let atr = $(e.target).attr('data-img');
  topImg = $('.img-wrapper[data-img="' + atr + '"]');
  //make it topmost
  topImg.css({ zIndex: '3' });
});
:root {
  --cursor-img-height: 30vh;
  --cursor-img-width: 30vw;
}

html,
body {
  background: #0E3741;
}

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

.special-element {
  width: 100%;
  height: 33vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2rem;
}

.special-element:nth-child(1) {
  background: lightblue;
}

.special-element:nth-child(2) {
  background: lightcoral;
}

.special-element:nth-child(3) {
  background: lightgreen;
}

#cursor {
  position: absolute;
  pointer-events: none;
  margin: 0;
  margin-top: calc(var(--cursor-img-height) * -0.5);
  margin-left: calc(var(--cursor-img-width) * -0.5);
  overflow: hidden;
  width: var(--cursor-img-width);
  height: var(--cursor-img-height);
}

.img-wrapper {
  position: absolute;
  bottom: 0;
  left: 0;
  width: var(--cursor-img-width);
  height: var(--cursor-img-height);
  overflow: hidden;
}

.img-wrapper>img {
  position: absolute;
  bottom: 0;
  left: 0;
  width: var(--cursor-img-width);
  height: var(--cursor-img-height);
  object-fit: fill;
  z-index: 1;
}

.special-element[data-img="one"]:hover~#cursor [data-img="one"],
.special-element[data-img="two"]:hover~#cursor [data-img="two"],
.special-element[data-img="three"]:hover~#cursor [data-img="three"] {
  animation: slide .8s ease-in-out;
}

@keyframes slide {
  from {
    height: 0px;
    transform: scale(1.2);
  }
  to {
    height: (--cursor-img-height);
    transform: scale(1);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.4/TweenMax.min.js"></script>

<section id="wrapper">
  <section class="special-element" data-img="one">food</section>
  <section class="special-element" data-img="two">animal</section>
  <section class="special-element" data-img="three">night</section>

  <div id="cursor">
    <div class="img-wrapper" data-img='one'>
      <img src="https://picsum.photos/id/674/400/200">
    </div>
    <div class="img-wrapper" data-img='two'>
      <img src="https://picsum.photos/id/433/400/200">
    </div>
    <div class="img-wrapper" data-img='three'>
      <img src="https://picsum.photos/id/901/400/200">
    </div>
  </div>
</section>


For a complete view, switch to full page mode.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Implementing fetch API in middleware in Next.js

Currently, I am utilizing a middleware in Next.js (https://nextjs.org/docs/advanced-features/middleware) for my project. However, I am encountering an issue when trying to send a request to the API. The error message displayed is: "unhandledRejection: Ty ...

Error: React Component not rendering correctly - Element Type Invalid

React Uncaught Error: Element type is invalid Encountering a problem in my React application where the following error message appears: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite compone ...

What is the best way to ensure the search box remains fixed in the top navigation bar while maintaining a fluid and responsive design?

I've been struggling as a novice programmer, and even with the help of more experienced programmers, we haven't been able to figure it out. I'm trying to integrate a search box into the top navigation that adjusts responsively to different ...

Unveiling the mysteries of JSONP in conjunction with AJAX

JSONP allows for bypassing the same origin policy in JavaScript by using <script> tags to load third party data. However, I am uncertain about how JSONP is utilized together with AJAX. My assumption is that: When an AJAX call is initiated, a <sc ...

Updating part of a page while also changing the navigation

Apologies in advance, as this is my first attempt at coding a website. I have a specific need where I want to update only one div on my web page when a link in the navigation bar is clicked. <body> <div id="wrapper"> <header id= ...

What is the best way to adjust the footer width to match the sidebar using Bootstrap 5?

Currently working on a Bootstrap 5 template for my website, but being new to it makes it a bit challenging. Specifically struggling with aligning the footer to fit the full width of the sidebar. <!DOCTYPE html> <html lang="en"> <head&g ...

PHP - contact form is live for just 2 hours daily

Hello, this is my first time here and I could really use some assistance. Please bear with me as English is not my strong suit compared to most people here, but I'll do my best to explain my query. So, I have a PHP script for a contact form on my web ...

How to use jQuery to adjust the opacity of a CSS background

I am facing a challenge with changing the transparency of a <div> element's background color using jQuery. An external API provides me with a hexadecimal value for the color: #abcdef I make use of jQuery (version 1.9) to apply this color using ...

Using React.js - What is the process for submitting a form automatically when the page loads?

Upon loading the page, I have a form that needs to be displayed. Here is the code snippet: <form name="myform" method="POST" className={classes.root} target="mydiv" action="https://example.com/submit" onLoad= ...

What are the steps to utilizing dynamic data from a file in JavaScript?

I've got a Python script constantly generating data, and I'm looking to use that data to make some changes to an object in JavaScript. Is there a method to accomplish this? ...

Uncheck the box for disabling the bottom row of HTML tables

I need help with disabling a check box under certain conditions. Specifically, I want to disable the check box if there is only one row in the table or if it's the last row, but for some reason it's not working as expected. Here is the HTML: &l ...

Styling Fonts in Safari with CSS

Because FixedSys doesn't appear correctly in Chrome or Safari, I switch it to Lucida Console. While this solution works for Chrome, I encounter a problem with Safari. Unless Lucida Console stands alone, the font will not display as desired. If there a ...

The styled-components seem to be having trouble injecting the necessary CSS to handle all the various props

I am curious to understand the potential reasons for styled-components not injecting all the necessary CSS into a page's header. In an existing project, I have defined a simple button like this: const Button = styled.button` background-color: ...

Why isn't my object updating its position when I input a new value?

<hmtl> <head> <!--<script src='main.js'></script>--> </head> <body> <canvas id='myCanvas'> </canvas> <script> function shape(x,y){ this.x=x; this.y=y; var canvas = document.get ...

The $POST method is failing to update the information

I've encountered an issue with my script that I can't seem to figure out. After numerous tests, it seems like the main problem lies within the Ajax request. Interestingly, I have used the Ajax request successfully in a previous version of my scri ...

Troubleshooting: Absence of Link Style in Lotus Notes 8.5 Email Client

While creating an HTML email and testing it with Litmus, I noticed that Lotus Notes 8.5 is not showing any link styles. Despite using traditional methods to ensure compatibility with older mail clients, the links are still not displaying correctly in Lotus ...

Is there a way to retrieve the width of the parent element in ReactJS from a child component?

The issue has been fixed: I forgot to include .current in my ref... I am trying to determine the width of the element that will hold my component. I came across a solution on SO, but unfortunately it did not work for me as it returned undefined: import R ...

Updating multiple values in MongoDB with varying data points

I need to update multiple documents in mongodb. Each document must be updated with a different value, which is provided in a JSON array. {_id :1 ,name :'A','place':'London'}, {_id :2 ,name :'B','place':&ap ...

What is the process for converting a URL or HTML document to a PDF using the html2pdf JavaScript library?

I am working on creating a button that utilizes the html2pdf library to convert an HTML page into a PDF. Instead of selecting an element with query selector or getElementById, I would like to pass a URL because the page I want to convert is not the same as ...

Tips for properly modifying an attribute within an array of objects in JavaScript using ReactJS

My array of objects looks like this: this.state = { itemSquare: [{ item: "bomb", status: false }, { item: "bomb", status: false }, { item: "bomb", status: false }, { item: "bomb", status: ...