How to make a CSS animation last after an element is no longer hovered?

Viewed 57

I have an issue with a CSS3 animation. I have a class who is helping me to animate an SVG, the name of this class is 'animateCircle'.

I want the animation to trigger when I hover over the "input".

I have create the following code:

jQuery('form.newsletter input[type="submit"]').hover(function() {


    jQuery('svg').addClass('animateCircle')

})

The problem is that the animation suddenly stops if I remove my cursor from the "input" element.

Ideally, I would like the animation to end (it lasts 2 seconds) and then the class (which triggers the animation) to delete itself. I have tried to put a setTimeOut but the problem remains the same: the animation is abruptly removed when the cursor is no longer on the "input".

if anyone has any idea, that would be greatly appreciated!

3 Answers

You must have some code not shown in the question that removes the class on mouseout; with the given code the animation would not stop.

You could use setTimeout to remove it, like this:

jQuery('form.newsletter input[type="submit"]').hover(function() {
    jQuery('svg').addClass('animateCircle');
    window.setTimeout(() => {
        jQuery('svg').removeClass('animateCircle')
    },2000);
})

That'd work, or close enough -- but it'd mean you have to define the duration twice: once in the CSS and once in the javascript. Would be easy to accidentally break that without realizing it. (It also means you could easily stack up a lot of simultaneous setTimeouts if the user hovers the element multiple times during the animation. In this particular case it'd be harmless for that removeClass to fire more than intended, but that wouldn't necessarily be the case if you were doing something with a cumulative effect. Also it's just not really good practice to fire events unnecessarily.)

Here's an example of how to remove the class specifically when the animation is complete, so that it can be triggered again the next time the input is hovered over:

// add the class on hover:
jQuery('button').hover(function() {
  jQuery('.animate').addClass('animateCircle')
})

// automatically remove the class when the animation ends:
jQuery('.animate').on('animationend', function() {
  jQuery(this).removeClass('animateCircle')
})
@keyframes example {
  0% {
    tranform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}

.animate {
  width: 100px;
  height: 100px;
  background-color: red;
}

.animate.animateCircle {
  background-color: blue; /* <-- so you can see when the class is active */
  animation-name: example;
  animation-duration: 2s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button>Hover me</button>


<div class="animate">Animation</div>

(I modified your html slightly to make it easier to demo, but it should be easy to see how to apply this to your html.)

First make sure the animate property in your CSS isn't set to run infinitely. Then you need to add an event listener to wait for the animation end to remove the class. Something like:

jQuery('form.newsletter input[type="submit"]').hover(function() {
    jQuery('svg').addClass('animateCircle')
})

$("svg").on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function() {
    $(this).removeClass('animateCircle')
})

For the sake of completeness (and because it's 2021), the following is vanilla Javascript, rather than a jQuery.

This approach attaches two EventListeners to the element which is to be animated:

  • mouseover adds the class which launches the animation
  • animationend removes the class which launches the animation

Working Example:

const square = document.getElementsByClassName('square')[0];

const addAnimateSquare = (e) => {
  e.target.classList.add('animateSquare');
}

const removeAnimateSquare = (e) => {
  e.target.classList.remove('animateSquare');
}

square.addEventListener('mouseover', addAnimateSquare, false);
square.addEventListener('animationend', removeAnimateSquare, false);
div {
  width: 100px;
  height: 100px;
  line-height: 100px;
  text-align: center;
  color: rgb(255, 255, 255);
  background-color: rgb(255, 0, 0);
  cursor: pointer;
}

div.animateSquare {
  animation: rotateSquare 2s linear;
}

@keyframes rotateSquare {
  100% {transform: rotate(1080deg);}
}
<div class="square">Hover me</div>


Further Notes:

Note that the javascript above is deliberately verbose for the sake of clarity.

The lines:

const addAnimateSquare = (e) => {
  e.target.classList.add('animateSquare');
}

const removeAnimateSquare = (e) => {
  e.target.classList.remove('animateSquare');
}

square.addEventListener('mouseover', addAnimateSquare, false);
square.addEventListener('animationend', removeAnimateSquare, false);

could be rewritten, just as straighforwardly, as:

square.addEventListener('mouseover', (e) => e.target.classList.add('animateSquare'));
square.addEventListener('animationend', (e) => e.target.classList.remove('animateSquare'));
Related