431

I'm running an animation on some elements that are set to opacity: 0; in the CSS. The animation class is applied onClick, and, using keyframes, it changes the opacity from 0 to 1 (among other things).

Unfortunately, when the animation is over, the elements go back to opacity: 0 (in both Firefox and Chrome). My natural thinking would be that animated elements maintain the final state, overriding their original properties. Is this not true? And if not, how can I get the element to do so?

The code (prefixed versions not included):

@keyframes bubble {
    0%   { transform:scale(0.5); opacity:0.0; }
    50%  { transform:scale(1.2); opacity:0.5; }
    100% { transform:scale(1.0); opacity:1.0; }
}
TylerH
  • 20,816
  • 57
  • 73
  • 92
Dan
  • 5,262
  • 3
  • 18
  • 27
  • 1
    I'll post my own repeat notice: http://stackoverflow.com/questions/9196694/css3-animation-scale At least mine has a more instructive title! – Dan Oct 20 '12 at 18:06
  • possible duplicate of [CSS3 Animate: How to have the object not revert to its initial position after animation has run?](http://stackoverflow.com/questions/6897724/css3-animate-how-to-have-the-object-not-revert-to-its-initial-position-after-an) – Michael Mullany Apr 26 '14 at 06:56

5 Answers5

736

Try adding animation-fill-mode: forwards;. For example like this:

-webkit-animation: bubble 1.0s forwards; /* for less modern browsers */
        animation: bubble 1.0s forwards;
tw16
  • 28,333
  • 7
  • 61
  • 64
Christofer Vilander
  • 15,864
  • 6
  • 30
  • 26
  • 2
    Yup that's it. Will check your answer when I can. If any CSS-heads wants to comment on the logic behind that being required, I'd love to know! – Dan Oct 20 '12 at 18:04
  • 10
    You can read about the animation-fill-mode property here - http://dev.w3.org/csswg/css3-animations/#animation-fill-mode-property Hope that helps! – Christofer Vilander Oct 20 '12 at 18:51
  • 9
    @Dan the `forwards` value of the `animation-fill-mode` property makes sure element would hold the last keyframe state of animation after animation ends. for example if your animation changes `width` from 0 to 100px, this property makes sure the element remains 100px wide after animation ends. – Farzad Yousefzadeh Feb 17 '16 at 15:23
  • 6
    don't forget to specify `100% / to` point in `@keyframe` otherwise it wont work. – Tomasz Mularczyk Jun 20 '17 at 18:33
  • animation-fill-mode:forwards did the trick for me also, but only after adding the '!important' imperative to the rule – shayuna Mar 27 '18 at 08:12
  • I had an issue with this approach: at least in Chrome, even after the animation ended, the renderer was still sucking up graphics resources, making the application less responsive. Check [my answer](https://stackoverflow.com/a/67032976/636561) for a different approach. – Luca Fagioli Apr 10 '21 at 09:55
70

If you are using more animation attributes the shorthand is:

animation: bubble 2s linear 0.5s 1 normal forwards;

This gives:

  • bubble animation name
  • 2s duration
  • linear timing-function
  • 0.5s delay
  • 1 iteration-count (can be 'infinite')
  • normal direction
  • forwards fill-mode (set 'backwards' if you want to have compatibility to use the end position as the final state[this is to support browsers that has animations turned off]{and to answer only the title, and not your specific case})
agiopnl
  • 950
  • 7
  • 14
30

IF NOT USING THE SHORT HAND VERSION: Make sure the animation-fill-mode: forwards is AFTER the animation declaration or it will not work...

animation-fill-mode: forwards;
animation-name: appear;
animation-duration: 1s;
animation-delay: 1s;

vs

animation-name: appear;
animation-duration: 1s;
animation-fill-mode: forwards;
animation-delay: 1s;
Taylor A. Leach
  • 1,717
  • 2
  • 22
  • 42
10

Use animation-fill-mode: forwards;

animation-fill-mode: forwards;

The element will retain the style values that is set by the last keyframe (depends on animation-direction and animation-iteration-count).

Note: The @keyframes rule is not supported in Internet Explorer 9 and earlier versions.

Working example

div {
  width: 100px;
  height: 100px;
  background: red;
  position :relative;
  -webkit-animation: mymove 3ss forwards; /* Safari 4.0 - 8.0 */
  animation: bubble 3s forwards;
  /* animation-name: bubble; 
  animation-duration: 3s;
  animation-fill-mode: forwards; */
}

/* Safari */
@-webkit-keyframes bubble  {
  0%   { transform:scale(0.5); opacity:0.0; left:0}
    50%  { transform:scale(1.2); opacity:0.5; left:100px}
    100% { transform:scale(1.0); opacity:1.0; left:200px}
}

/* Standard syntax */
@keyframes bubble  {
   0%   { transform:scale(0.5); opacity:0.0; left:0}
    50%  { transform:scale(1.2); opacity:0.5; left:100px}
    100% { transform:scale(1.0); opacity:1.0; left:200px}
}
<h1>The keyframes </h1>
<div></div>
Deepu Reghunath
  • 6,468
  • 1
  • 30
  • 41
3

I had an issue using forwards: at least in Chrome, even after the animation ended, the renderer was still sucking up graphics resources, making the application less responsive.

An approach that does not cause this trouble is by using an EventListener.

CSS animations emit events, so you can use the animationend event to intervene when the animation ends.

CSS

.fade_in {
  animation: fadeIn 2s;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

JavaScript

const element = document.getElementById("element-to-be-animated");

element.addEventListener("animationend", () => {
    // Set your final state here. For example:
    element.style["opacity"] = 1;
}, { once: true });

The option once: true tells the engine to remove the event listener after its execution, leaving your application fresh and clean.

I have created a JSFiddle to show how it works.

Luca Fagioli
  • 11,783
  • 5
  • 52
  • 48