dx_over_dt
dx_over_dt

Reputation: 14318

CSS3 changing animation duration (speed) mid-animation

I'm not sure if this is a duplicate or not, so forgive me.

Question

Is it possible to change the animation-duration without resetting the animation? If not, is it possible to wait until the final keyframe is completed before removing the animation and re-adding it to start the animation at the slower speed (or even wait until any keyframe is complete)?

Background

I'm making an app that allows people to create groups. I work at a church, and different groups are for different demographics (e.g. children, men, women, all adults, etc). Groups may be for a single demographic or many. Groups may also specify whether childcare is handled by the group or if the parent must take care of it.

Group demographic selection

We've found that when creating a group intended for adults but that provides childcare at the house the group meets at, people select "Children" which indicates to us that the group is for children, which it is not.

I only have 570px by 456px to work with (against my objections, the group submission page is loaded in a popup iframe), so I had to get creative with layout. Previously (ie, before bootstrap), I had an ugly layout with smaller inputs, and an ugly message explaining that, in the case described above, they should not select children, and it worked to a degree.

Now, I have a blue info button that uses a bootstrap popover to display the message.

Popover message

This works to a lesser degree, as I suspect people are not clicking the button, as "Who's invited?" seems fairly self explanatory.

My solution is to make the info-sign bounce if they select more than one demographic, and bounce twice as fast if one of the selected checkboxes is "Children".

Code

I've created the classes and added the (simplified) JavaScript to do this.

var iGlyph = $("#glyphInfo");
var btnBounce = $("#btnToggleBounce");
var btnFast = $("#btnToggleFast");
var spanDur = $("#spanDuration");
var spanClass = $("#spanClass");

function updateText() {
  spanDur.text(iGlyph.css("animation-duration"));
  spanClass.text(iGlyph.prop("class"));
}

$(function() {
  btnBounce.click(function() {
    iGlyph.toggleClass("bounce");
    updateText();
  });

  btnFast.click(function() {
    iGlyph.toggleClass("bounce-fast");
    updateText();
  });

  updateText();
});
/* LESS-generated CSS */

.bounce {
  -webkit-animation: bounceKeyframe infinite;
  -o-animation: bounceKeyframe infinite;
  animation: bounceKeyframe infinite;
  -webkit-animation-duration: 0.7s;
  animation-duration: 0.7s;
}

.bounce.bounce-fast {
  -webkit-animation-duration: 0.35s;
  animation-duration: 0.35s;
}

@keyframes bounceKeyframe {
  0% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
  }
  35% {
    -webkit-transform: translate(0, -0.9em);
    -ms-transform: translate(0, -0.9em);
    -o-transform: translate(0, -0.9em);
    transform: translate(0, -0.9em);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }
  70% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: linear;
    animation-timing-function: linear;
  }
}

@-webkit-keyframes bounceKeyframe {
  0% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
  }
  35% {
    -webkit-transform: translate(0, -0.9em);
    -ms-transform: translate(0, -0.9em);
    -o-transform: translate(0, -0.9em);
    transform: translate(0, -0.9em);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }
  70% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: linear;
    animation-timing-function: linear;
  }
}

@-moz-keyframes bounceKeyframe {
  0% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
  }
  35% {
    -webkit-transform: translate(0, -0.9em);
    -ms-transform: translate(0, -0.9em);
    -o-transform: translate(0, -0.9em);
    transform: translate(0, -0.9em);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }
  70% {
    -webkit-transform: translate(0, 0);
    -ms-transform: translate(0, 0);
    -o-transform: translate(0, 0);
    transform: translate(0, 0);
    -webkit-animation-timing-function: linear;
    animation-timing-function: linear;
  }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="text-align: center; margin-top: 5%">
  <div class="btn btn-info">
    <span id="glyphInfo" class="glyphicon glyphicon-info-sign" style="line-height: 22px"></span>
  </div>
</div>
<div style="text-align: center">
  animation-duration: <span id="spanDuration"></span>
</div>
<div style="text-align: center">
  classes: <span id="spanClass"></span>
</div>
<div style="text-align: center; margin-top: 15px">
  <div class="btn btn-default" id="btnToggleBounce">Toggle Bounce</div>
  <div class="btn btn-default" id="btnToggleFast">Toggle Fast</div>
</div>

This works in Firefox, though when you toggle .bounce-fast, the animation restarts (skips). Not surprisingly, Internet Explorer bounces the icon completely off screen (looks like it doesn't like using both em and px units), but animation-duration-wise, it acts the same as Chrome, which uses whatever animation-duration was set to when the animation rule was set, and never overrides it until the animation rule is unset.

Problem

So, ideally, I would be able to set the animation-duration somehow without having to reset the animation completely. I want a smooth transition from one speed to the other, without the icon jumping.

Is this possible?

Upvotes: 2

Views: 3401

Answers (1)

Patrick Gunderson
Patrick Gunderson

Reputation: 3281

Unfortunately there is no way to do this with pure CSS animations. The nature of CSS animations is that the calculations for the transition only have to happen once (when the animation is called) in order to speed them up.

If you want to change speed of animations you'll need to use Javascript (which is nearly as fast, sometimes faster than, CSS animations)

I particularly like Greensock and Velocity

Upvotes: 1

Related Questions