Reputation: 9597
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.
Upvotes: 4
Views: 1851
Reputation: 89750
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.
Upvotes: 6
Reputation: 652
You can probably achieve it by using java script to remove and add a new class after a button is clicked.
something like this. Basically just create a new css class with new that sets a specific amount of time for the animation to run.
For Example if the animation you have running, runs indefinitely, then just create a new_class with similar values but with a definite time like 2s or 4s etc. After those 4s the animation should stop.
$(document).click(function (e) {
$el = $(e.target);
if ($el.hasClass('Button_class')) {
$(".moving_image_class").toggleClass('new_class');
} else {
$(".moving_image_class").removeClass('New_class');
}
});
Upvotes: 0
Reputation: 37701
Make a class with a CSS transition for the background position, and when the button is clicked, add that class and remove your animation class at the same time. Make sure you use the same units (pixels, percentages...) in both cases.
Upvotes: 1