I'm not entirely sure that this will be possible without a different approach that doesn't use CSS animations. The issue is that the animation does not normalize whenever you change the speed. It is always animating from 0% of the animation to 100% of the animation. Every time you adjust the animation-duration
, you're going to re-interpolate using the current position in the animation.
In other words, if you change from animation-duration: 25
to 50
at t=12
, well the animation was halfway finished (180 degrees); now it's only a quarter finished (90 degrees). You can't control t
though, that's the browser's. If you could, you would want to set t
to remain where it was in the interpolation, in this example, t=25
, so that you remain at the same percentage complete of the animation that you were, but you stretch the remaining time.
I modified your script a little to try and show what I'm describing a little better. It will increment the speed by 0.25
every second between speed 0 and 5. You can kind of see how the problem is that the browser controlled t
is the issue.
You can rewrite this in order to control t
yourself with JavaScript, but I think you'll have to drop the CSS animations.
To talk a little bit more to the point of this browser controlled t
variable, take a look at this article on CSS-Tricks: Myth Busting: CSS Animations vs. JavaScript
Some browsers allow you to pause/resume a CSS keyframes animation, but
that's about it. You cannot seek to a particular spot in the
animation, nor can you smoothly reverse part-way through or alter the
time scale or add callbacks at certain spots or bind them to a rich
set of playback events. JavaScript provides great control, as seen in
the demo below.
That's your problem, you want to be able to change the duration of your animation, but then also seek to the correct spot in the animation.
$(function() {
var speed = parseInt($("#slider").val(), 10);
$("#speed").html(speed);
$("#loading").css("animation-duration", 50 / speed + "s");
var forward = true;
setInterval(function() {
speed += (forward ? 0.25 : -0.25);
if (speed >= 5) {
forward = false;
} else if (speed <= 0) {
forward = true;
}
$("#loading").css("animation-duration", 50 / speed + "s");
$("#slider").val(speed);
$("#speed").html(speed);
}, 1000);
});
#loading {
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 50% 50%;
animation: rotateRight infinite linear;
animation-duration: 0;
}
@keyframes rotateRight {
100% {
transform: rotate(360deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<img id="loading" src="//placehold.it/100">
<input type="range" min="0" max="100" value="0" step=".25" class="slider" id="slider" value="0">
<p>Speed: <span id="speed"></span></p>