6
votes

I've always thought that CSS3 Animations (differently from CSS3 Transitions) once started, always finish the job, no matter if the selector is not matching anymore the element that activated them.

I'm realizing today that I was probably wrong.

In the following example, an animation is triggered by the :focus and :active pseudo-classes. Focus on the first textfield:

  • if you press the tab button slowly, you will see the animations starting and ending correctly;
  • if you press the tab button quickly, you will see that once a new element get the focus, the old element's animation immediately ends and disappear.

@-webkit-keyframes pressed {    
    0%, 100% { transform : scale(1); }
         50% { transform : scale(2); }
}
@keyframes pressed {    
    0%, 100% { transform : scale(1); }
         50% { transform : scale(2); }
}
a:focus, a:active {
    -webkit-animation : pressed 2s; 
            animation : pressed 2s; 
}

a, input {
          border : 1px solid silver; 
         padding : 5px;
          height : 40px;
     line-height : 28px;
          margin : 0px;
         display : inline-block;
           width : 33.3%;
      box-sizing : border-box;  
      background : white; 
  vertical-align : middle;
}

a { 
           color : dodgerBlue; 
 text-decoration : none;}

input {
           color : red;
}
<input type="text" id="foo" value="Start here, then press tab" /><a  href = "#">
Lorem
</a><a  href = "#">
Ipsum
</a><a  href = "#">
dolor
</a><a  href = "#">
sit
</a><a  href = "#">
amet
</a><a  href = "#">
consectetur 
</a><a  href = "#">
adipiscing 
</a><a  href = "#">
elit
</a>

I know I can make it end smoothly (on some browser, eg. Firefox yes, Chrome no) by applying:

    a { transition: all 2s ease; }

so that if it's loaded up to (for example) 40%, it will animate back from 40% to 0% instead of immediately dropping to 0%.

- I also know that I can use jQuery animations instead of CSS3 animation and make it work that way; (EDIT: according to the comment, not even jQuery animations will work this way, if I got that right)

What I'm asking here, as a CSS3 Animation newbie, is:

is there a pure CSS3 way to force the animation to run up to 100%, no matter if the initial condition is not valid anymore ?

1
Doesn't look like it. Even Animations level 2 simply provides a DOM event for this which means you can't even control it through scripting right now until animationcancel is implemented.BoltClock
Not exactly relevant but are you able to animate it back smoothly with transition? I have never seen that prior and it doesn't happen with the snippet for me (in Chrome v38).Harry
@BoltClock: so the answer is "no, not even with jQuery" ? I've not tried yet, just assumed that by scripting it would have worked. Well, I guess I'll figure something out with some JS magic, then :/ Thanks, feel free to add it as an answer.Andrea Ligios
@Harry: you're right, it works perfectly on Firefox, but it doesn't work on Chrome (neither with animation nor -webkit-animation... ) :|Andrea Ligios
@Harry yes, that's the way I do this kind of things, eg. for IE retrocompatibility when needed (generally with jQuery, though). Feel free to add it as an answer, I always upvote every (useful) answer. P.S: I'm not an expert in mobile development neither... actually, I'm not even a front-end developer :D I just like taking care of this part too, especially because our super expensive front-end guys are even more sloppy than me :| so I'm going full-stack and breadth-first.Andrea Ligios

1 Answers

1
votes

As discussed in comments there is currently no way to force an animation to complete one full cycle even after the selector rule which originally applied the animation is no longer applicable.

The only way to achieve this is by using scripting. Below is a sample snippet using JavaScript. What this does is to add a class (that has the animation property set) to the element when it gains focus and then remove it only when the animation ends.

Note: I have used webkitAnimationEnd event in the snippet and so it would not work in other browsers. The code also needs more fine tuning because it currently removes the class only on animation end. So, if you tab out and tab in before one cycle is completed then nothing happens.

window.onload = function() {
  var anchors = document.querySelectorAll('a');
  for (var i = 0; i < anchors.length; i++) {
    anchors[i].addEventListener('focus', function() {
      addanim(this);
    });
    anchors[i].addEventListener('webkitAnimationEnd', function() {
      endanim(this);
    });
  }

  function addanim(el) {
    el.classList.add('focus');
  }

  function endanim(el) {
    el.classList.remove('focus');
  }
}
@keyframes pressed {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(2);
  }
}
.focus {
  animation: pressed 2s;
}
a,
input {
  border: 1px solid silver;
  padding: 5px;
  height: 40px;
  line-height: 28px;
  margin: 0px;
  display: inline-block;
  width: 33.3%;
  box-sizing: border-box;
  background: white;
}
a {
  color: dodgerBlue;
  text-decoration: none;
}
input {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>

<input type="text" id="foo" value="Start here, then press tab" />
<a href="#">Lorem</a>
<a href="#">Ipsum</a>
<a href="#">dolor</a>
<a href="#">sit</a>
<a href="#">amet</a>
<a href="#">consectetur</a>
<a href="#">adipiscing</a>
<a href="#">elit</a>

The animationcancel event mentioned in comments (by BoltClock) could have been more useful for our case but it is just an event that is fired when an abnormal end to the animation is encountered. We would still have to write our own code to make it continue till the end of a cycle.