I have an animation moving the background-position
of an image with keyframes, and this works fine.
Although, when the user click a button, I would like to pause the animation of the background but with a transition, slowing down then stopping the background-position
from moving.
I searched for something similar to that but I didn't find anything, so I was wondering if any of you would have an idea how I could do that?
Thanks.
NO. You cannot achieve this with CSS animations while using only one element for a few reasons and they are as follows:
paused
is an immediate action.Once an animation is applied on an element, it takes control of the property until it is removed. So, changing background-position
with JS will also have no effect (even if it is actually paused).
From W3C Spec:
CSS Animations affect computed property values. During the execution of an animation, the computed value for a property is controlled by the animation. This overrides the value specified in the normal styling system.
A sample can be seen in the below snippet. Along with the animation-play-state: paused
, the class that is toggled on also sets a specific value for background-position
(with important) but it has absolutely no effect on the element. The commented out portions of the JS is how I had tried to produce a gradual stop at a slower rate but it just does not work.
var el = document.getElementsByTagName('div')[0];
var btn = document.getElementById('stop');
var i = 0,
bgPosX,
interval,
state = 'running';
btn.addEventListener('click', function() {
/* state = (state == 'running') ? 'paused' : 'running';
console.log(state);
if (state == 'paused') {
var currPos = window.getComputedStyle(el).backgroundPositionX;
bgPosX = parseInt(currPos.replace('px', ''), 10);
interval = setInterval(function() {
slowPause(bgPosX);
}, 1);
} else {
el.style.backgroundPosition = null;
} */
el.classList.toggle('paused');
});
/*function slowPause(currPosX) {
el.style.backgroundPosition = currPosX + (i * 0.2) + 'px 0%';
console.log(el.style.backgroundPositionX);
i++;
if (i >= 1000) {
clearInterval(interval);
i = 0;
console.log('cleared');
}
}*/
.animated-bg-pos {
height: 100px;
width: 200px;
background-image: linear-gradient(to right, red 25%, blue 25%, blue 50%, orange 50%, orange 75%, green 75%);
background-size: 800px 100%;
animation-name: animate-bg-pos;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 4s;
}
body div.animated-bg-pos.paused {
animation-play-state: paused;
background-position: 200px 0% !important;
}
@keyframes animate-bg-pos {
from {
background-position: 0px 0%;
}
to {
background-position: 800px 0%;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='animated-bg-pos'></div>
<button id='stop'>Stop Animation</button>
Removal of the animation will cause the element to snap back to its original position immediately. It does not transition back gradually. You can read a bit about it here.
Considering all this, you would have to rewrite your entire animation using jQuery or JavaScript if you have to get the required behavior. A very rough implementation with timers and constant change of the background-position
is available in the below snippet.
/* initial variable declarations */
var el = document.getElementsByTagName('div')[0];
var btn = document.getElementById('stop');
var i = 0,
currPos = 0,
pauseInterval, runningInterval,
running = true,
bgSize = parseInt(window.getComputedStyle(el).backgroundSize.split('px')[0], 10);
/* toggle button listener */
btn.addEventListener('click', function() {
running = !running; // toggle state
if (!running) {
i = 0;
currPos = parseInt(el.style.backgroundPositionX.replace('px', ''), 10);
clearInterval(runningInterval); /* stop the normal animation's timer */
pauseInterval = setInterval(function() {
slowPause(currPos); /* call the slow pause function */
}, 10);
} else {
i = 0;
currPos = parseInt(el.style.backgroundPositionX.replace('px', ''), 10);
clearInterval(pauseInterval); /* for safer side, stop pause animation's timer */
runningInterval = setInterval(function() {
anim(currPos); /* call the normal animation's function */
}, 10);
}
});
/* slowly pause when toggle is clicked */
function slowPause(currPosX) {
el.style.backgroundPosition = (currPosX + (i * .025)) % bgSize + 'px 0%';
i += 10;
if (i >= 1000) { /* end animation after sometime */
clearInterval(pauseInterval);
i = 0;
}
}
/* increment bg position at every interval */
function anim(currPosX) {
el.style.backgroundPosition = (currPosX + (i * .25)) % bgSize + 'px 0%';
i += 10;
}
/* start animation on load */
runningInterval = setInterval(function() {
anim(currPos);
}, 10);
.animated-bg-pos {
height: 100px;
width: 200px;
background-image: linear-gradient(to right, red 25%, blue 25%, blue 50%, orange 50%, orange 75%, green 75%);
background-size: 800px 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='animated-bg-pos'></div>
<button id='stop'>Toggle Animation State</button>
Note: The above snippet is only a rough implementation to give an idea. I am not a JS expert and feel that the JS used in the snippet can be optimized a lot.
If you don't have a problem with adding extra wrapper elements around the one that is being animated then you can make use of the approach mentioned in vals' answer here.
var el = document.getElementsByTagName('div')[1];
var btn = document.getElementById('stop');
btn.addEventListener('click', function() {
el.classList.toggle('paused');
});
.cover {
position: relative;
width: 200px;
height: 100px;
border: 1px solid;
overflow: hidden;
}
.animated-bg-pos {
position: absolute;
top: 0px;
left: 0px;
height: 100px;
width: 240px;
left: -40px;
background-image: linear-gradient(to right, red 25%, blue 25%, blue 50%, orange 50%, orange 75%, green 75%);
background-size: 800px 100%;
animation: animate-bg-pos 4s linear infinite;
transition: transform 1s ease-out;
}
.paused {
animation-play-state: paused;
transform: translateX(40px);
}
@keyframes animate-bg-pos {
from {
background-position: 0px 0%;
}
to {
background-position: 800px 0%;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='cover'>
<div class='animated-bg-pos'></div>
</div>
<button id='stop'>Stop Animation</button>
Note: All credits for the above approach goes to vals. I have only adapted his approach to make this answer more complete.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With