Skip to content Skip to sidebar Skip to footer

Animation Paused With Transition

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 t

Solution 1:

NO. You cannot achieve this with CSS animations while using only one element for a few reasons and they are as follows:

  • An animation's play state change to 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: 800px100%;
      animation-name: animate-bg-pos;
      animation-timing-function: linear;
      animation-iteration-count: infinite;
      animation-duration: 4s;
    }
    bodydiv.animated-bg-pos.paused {
      animation-play-state: paused;
      background-position: 200px0%!important;
    }
    @keyframes animate-bg-pos {
      from {
        background-position: 0px0%;
      }
      to {
        background-position: 800px0%;
      }
    }
    <scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><divclass='animated-bg-pos'></div><buttonid='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.

  • Applying transition and animation on the same property doesn't work well across browsers. It still results in the animation taking full control and renders the transition useless. Read more here.
  • Finally, even if you somehow get the removal of animation and use JS to slowly transition it to an intermediate state this will not resemble the "pause" behavior. The reason is because when you re-apply the animation it will again start from the first frame and not where you stopped it.

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 stateif (!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 */functionslowPause(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 */functionanim(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: 800px100%;
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><divclass='animated-bg-pos'></div><buttonid='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: 800px100%;
  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: 0px0%;
  }
  to {
    background-position: 800px0%;
  }
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><divclass='cover'><divclass='animated-bg-pos'></div></div><buttonid='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.

Solution 2:

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.

Solution 3:

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');
  }

});

Post a Comment for "Animation Paused With Transition"