86

I'm making a simple landing page driven by CSS3. To make it look awesome there's an <a> plopping up:

@keyframes splash {
    from {
        opacity: 0;
        transform: scale(0, 0);
    }
    50% {
        opacity: 1;
        transform: scale(1.1, 1.1);
    }
    to {
        transform: scale(1, 1);
    }
}

And to make it even more awesome I added a hover animation:

@keyframes hover {
    from {
        transform: scale(1, 1);
    }
    to {
        transform: scale(1.1, 1.1);
    }
}

But there comes the problem! I assigned the animations like this:

a {
    /* Some basic styling here */

    animation: splash 1s normal forwards ease-in-out;
}
a:hover {
    animation: hover 1s infinite alternate ease-in-out;
}

Everything works just fine: The <a> splashes into the users face and has a nice vibration when he hovers it. Bit as soon as the user blurs the <a> the smooth stuff ends abruptly and the <a> repeats the splash-animation. (Which is logical to me, but I don't want it to) Is there some way to solve this problem without some JavaScript Class Jiggery Pokery?

Butsuri
  • 738
  • 9
  • 14
buschtoens
  • 8,091
  • 9
  • 42
  • 60

9 Answers9

55

After hours of googling: No, it's not possible without JavaScript. The animation-iteration-count: 1; is internally saved in the animation shothand attribute, which gets resetted and overwritten on :hover. When we blur the <a> and release the :hover the old class reapplies and therefore again resets the animation attribute.

There sadly is no way to save a certain attribute states across element states.

You'll have to use JavaScript.

buschtoens
  • 8,091
  • 9
  • 42
  • 60
  • 2
    Try adding `:not(:hover)` to the selector of the splash animation. – Blaise Apr 05 '14 at 08:59
  • 1
    @silvinci can you give Javascript code that solved this issue? – Dchris Apr 21 '14 at 22:49
  • 3
    @Dchris Just add a a class like "animate-this" and remove it after the animation finished. – buschtoens Apr 25 '14 at 06:52
  • 1
    @buschtoens How did you manage to know when the animation has finished with JS? – tonix Aug 17 '19 at 17:40
  • @buschtoens I'm sure you meant to provide more information but found yourself unable at the time. When you can, please provide more context as to why your answer could not be solved the way you wanted. – Jacksonkr Oct 20 '20 at 15:38
  • You could also not use shorthand at all and only set the properties you actually want to change on `:hover`. For example, `animation-name` and `animation-direction`. That would prevent resetting everything. See https://developer.mozilla.org/en-US/docs/Web/CSS/animation for details. – Mikko Rantalainen Sep 10 '21 at 14:23
42

If I understand correctly that you want to play the animation on A only once you have to add

animation-iteration-count: 1

to the style for the a.

Strelok
  • 50,229
  • 9
  • 102
  • 115
  • 1
    Yup. Works in Chrome since v43, and most current browsers: https://developer.mozilla.org/en-US/docs/Web/CSS/animation-iteration-count – Chris Moschini Jan 19 '21 at 19:44
29

It can be done with a little bit of extra overhead.

Simply wrap your link in a div, and separate the animation.

the html ..

<div class="animateOnce">
    <a class="animateOnHover">me!</a>
</div>

.. and the css ..

.animateOnce {
    animation: splash 1s normal forwards ease-in-out;
}

.animateOnHover:hover {
    animation: hover 1s infinite alternate ease-in-out;
}
Butsuri
  • 738
  • 9
  • 14
22

I just got this working on Firefox and Chrome. You just add/remove the below class accordingly to your needs.

.animateOnce {
  -webkit-animation: NAME-OF-YOUR-ANIMATION 0.5s normal forwards; 
  -moz-animation:    NAME-OF-YOUR-ANIMATION 0.5s normal forwards;
  -o-animation:      NAME-OF-YOUR-ANIMATION 0.5s normal forwards;
}
Ricardus
  • 739
  • 2
  • 8
  • 15
3

Just use

animation: hover 1s ease-in-out forwards;
Rajanand
  • 105
  • 8
  • 3
    While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 09 '22 at 17:21
1

An easy solution to solve this problem is by just adding more seconds to the animation in a:hover and taking advantage of the transitions in @keyframes

a:hover {
        animation: hover 200s infinite alternate ease-in-out;
    }

Just make the progression of @keyframes go faster by using percentages.

@keyframes hover {
    0% {
        transform: scale(1, 1);
    }
    1% {
        transform: scale(1.1, 1.1);
    }
    100% {
        transform: scale(1.1, 1.1);
    }
}

200 seconds or 300 seconds in the animation is more than enough to make sure the animation doesn't restart. A normal person won't last more than a few seconds hovering an image.

Gass
  • 7,536
  • 3
  • 37
  • 41
0

Impossible in CSS only, you need a javascript workaround. As already explained by some here, the animation-iteration-count property is reset on a :hover. The best is to do everything in javascript, but for reasons of ease of customization of the code you may want to keep the possibility of doing something in CSS.

So, in JS :

// adding a class to the html tag, during the animation time 
const startPage = (() => {
  const html = document.documentElement,
        s = 'start'
  html.classList.add(s)
  window.addEventListener('load', function() {
    setTimeout(() => {
      html.classList.remove(s)
    }, 1500) // the time must be at least equal to the duration of the CSS animation (personally I put a little more).
  })
})()

And for the CSS:

/* the presence of the `.start` class conditions the animation */
.start .leaflet-marker-pane {
    animation: animDrop 1s ease;
}
Olivier C
  • 899
  • 1
  • 13
  • 14
-1

The following code without "iteration-count: 1" was resulting in all line items pulsing after entering, until the last item loaded, even though 'pulse was not being used.

<li class="animated slideInLeft delay-1s animation-iteration-count: 1"><i class="fa fa-credit-card" aria-hidden="true"></i> 1111</li>


<li class="animated slideInRight delay-1-5s animation-iteration-count: 1"><i class="fa fa-university" aria-hidden="true"></i> 222222</li>

<li class="animated lightSpeedIn delay-2s animation-iteration-count: 1"><i class="fa fa-industry" aria-hidden="true"></i> aaaaaa</li>

<li class="animated slideInLeft delay-2-5s animation-iteration-count: 1"><i class="fa fa-key" aria-hidden="true"></i> bbbbb</li>

<li class="animated slideInRight delay-3s animation-iteration-count: 1"><i class="fa fa-thumbs-up" aria-hidden="true"></i> ccccc</li>
Taher A. Ghaleb
  • 5,120
  • 5
  • 31
  • 44
-1

So i just found a solution for that: In the hover animation do this:

animation: hover 1s infinite alternate ease-in-out,splash 1;
Haki
  • 1
  • 4