Run CSS3 animation only once (at page loading)
Asked Answered
E

9

91

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?

Eskill answered 13/12, 2011 at 0:20 Comment(0)
E
57

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.

Eskill answered 16/3, 2012 at 18:40 Comment(6)
Try adding :not(:hover) to the selector of the splash animation.Saprophagous
@silvinci can you give Javascript code that solved this issue?Kherson
@Kherson Just add a a class like "animate-this" and remove it after the animation finished.Eskill
@Eskill How did you manage to know when the animation has finished with JS?Coadjutant
@Eskill 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.Female
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 developer.mozilla.org/en-US/docs/Web/CSS/animation for details.Cohobate
B
46

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.

Bierce answered 13/12, 2011 at 5:17 Comment(1)
Yup. Works in Chrome since v43, and most current browsers: developer.mozilla.org/en-US/docs/Web/CSS/…Nicoline
H
31

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

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

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

.animateOnHover:hover {
  animation: hover 1s infinite alternate ease-in-out;
}
@keyframes splash {
    from {
        opacity: 0;
        transform: scale(0, 0);
    }
    50% {
        opacity: 1;
        transform: scale(1.1, 1.1);
    }
    to {
        transform: scale(1, 1);
    }
}

@keyframes hover {
    from {
        transform: scale(1, 1);
    }
    to {
        transform: scale(1.1, 1.1);
    }
}
<div class="animateOnce">
  <a class="animateOnHover">me!</a>
</div>
Hadji answered 12/6, 2013 at 2:19 Comment(1)
Nice idea. But in the end I shall prefere JS extra code over HTML overhead. Still +1 ;)Eskill
D
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;
}
Davide answered 30/7, 2014 at 7:31 Comment(0)
S
9

Just use

animation: hover 1s ease-in-out forwards;
Splenius answered 8/1, 2022 at 6:15 Comment(1)
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, 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.Fermium
B
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.

Bilocular answered 18/1, 2021 at 21:27 Comment(0)
M
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;
}
Monmouthshire answered 10/3, 2022 at 22:22 Comment(0)
U
-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>
Umbra answered 28/11, 2018 at 1:53 Comment(0)
K
-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;
Kippy answered 8/11, 2020 at 18:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.