44

I've created a simple bounce animation which i'm applying to the :hover state of an element:

@keyframes bounce {
    0% {
      top: 0;
      animation-timing-function: ease-out;
    }
    17% {
      top: 15px;
      animation-timing-function: ease-in;
    }
    34% {
      top: 0;
      animation-timing-function: ease-out;
    }
    51% {
      top: 8px;
      animation-timing-function: ease-in;
    }
    68% {
      top: 0px;
      animation-timing-function: ease-out;
    }
    85% {
      top: 3px;
      animation-timing-function: ease-in;
    }
    100% {
      top: 0;
    }
}

.box:hover { 
    animation: bounce 1s;
}

The animation works fine, with the exception that when you remove your cursor from the element it abruptly stops. Is there anyway to force it to continue the set number of iterations even if the mouse has exited? Basically what I'm looking for here is an animation triggered by the :hover state. I'm not looking for a javascript solution. I haven't seen anyway to do this in the spec, but maybe there's an obvious solution I've missed here?

Here's a fiddle to play with: http://jsfiddle.net/dwick/vFtfF/

0

7 Answers 7

40

I'm afraid that the only way to solve this is with a bit of javascript, you must add the animation as a class and then remove it when the animation finishes.

$(".box").bind("webkitAnimationEnd mozAnimationEnd animationend", function(){
  $(this).removeClass("animated")  
})

$(".box").hover(function(){
  $(this).addClass("animated");        
})

http://jsfiddle.net/u7vXT/

2
  • was hoping to avoid javascript, but i figured this was the only way.
    – David Wick
    Commented Oct 9, 2011 at 23:42
  • 1
    the browser-agnostic event name should be all lowercase: animationend
    – jackocnr
    Commented Oct 20, 2015 at 23:01
8

I created a JsFiddle with this answer from the same post https://stackoverflow.com/a/7697786/8335898 using pure Javascript if anyone wants to use it.

const elements = document.getElementsByClassName('box');

for (let i = 0; i <= elements.length; i++) {
  elements[i].addEventListener('animationend', function(e) {
    elements[i].classList.remove('animated');
  });

 elements[i].addEventListener('mouseover', function(e) {
   elements[i].classList.add('animated')
 })
}
4

Same answer with @methodofaction but for anyone using React:

import React, { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

export default function Icon({ icon }) {
    const [animated, setAnimated] = useState(false);

    return (
        <div
            onMouseEnter={() => setAnimated(() => true)}
            onAnimationEnd={() => setAnimated(() => false)}
        >
            <FontAwesomeIcon icon={icon} className={animated ? 'animated' : ''} />
        </div>
    );
}
3

just to improve Duopixel answer, when runnig infinite animitation I have to do:

$(".box").css("animation-iteration-count", "1"); 
$(".box").bind("webkitAnimationEnd mozAnimationEnd animationEnd", function(){
  $(this).removeClass("animated")  
})
$(".box").hover(function(){
  $(".box").css("animation-iteration-count", "infinite"); 
  $(this).addClass("animated");        
})

This just not abruptly end the animation.

5
  • What if i want to stop the animation gracefully when i remove hover ? and then again start infinite animation when i hover again ?
    – Vinay
    Commented Dec 15, 2015 at 6:31
  • You can implement mouseleave event of the box, there you can add this code. Commented Dec 16, 2015 at 13:21
  • 3
    Developed a solution :D Here's the fiddle if it helps anyone ! jsfiddle.net/sSYYE/33
    – Vinay
    Commented Dec 17, 2015 at 13:44
  • Thanks @Vinay! Your solution was really helpful! Commented Jul 31, 2018 at 23:23
  • is it possible to ensure animation end but in the reverse side ?
    – DiaJos
    Commented May 17, 2019 at 0:11
3

This won't work in all situations, and won't work for OP without some compromises but I solved this problem by adding an animation to the :not(:hover) selector:

@keyframes stopBounce {
    0% {
         top: 15px;
    }
    100% {
        top: 0px;
    }
}

@keyframes bounce {
    ops: bounce code
}


.box{
    top: 0px;
    transition: top 250ms 1000ms ease-in-out,
}
.box:hover{
    animation-name: bounce;
    animation-fill-mode: both;
    animation-duration: 250ms;
}
.box:not(:hover){
    animation-name: stopBounce;
    animation-duration: 250ms;
    animation-delay: 1000ms;
    animation-fill-mode: both;
}

So, what this doesn't do is allow the animation to continue all the way through. As far as I can tell a pure CSS solution to that is impossible. What it does do is allow it to smoothly transition back to it's starting position. The trick is having two selectors, only one of which can be active at any one time.

What this allows us to do is have an animation that plays when the user hovers, and a separate animation that plays whenever the user stops hovering. Since both of these animations can be controlled, it allows us to ensure that the transition between them is smooth.

Like I said, this doesn't fully solve the problem, but it doesn't use JavaScript and will keep things smooth.

1
  • This is an amazingly elegant solution without JS getting involved. Many Kudos.
    – Randy Hall
    Commented Mar 1, 2022 at 1:49
1

A simple trick will do the job :

-webkit-animation:swing 3600ms ease-in-out 6000s;
-webkit-transform-origin:top;

Set the 'delay' with an high value on the element (not :hover).

From: Stackoverflow - Robert McKee

0
0

CSS might help in some cases but not all, below is the code that will animate letter spacing on both hover and after hover.

h1
{
    -webkit-transition:all 0.3s ease;
}

h1:hover
{
    -webkit-transition:all 0.3s ease;
    letter-spacing:3px;
}
<body>
    <h1>Hello</h1>
</body>

1
  • 3
    That's a transition, not an animation. Commented Jan 10, 2021 at 20:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.