动画已暂停转换 [英] Animation paused with transition

查看:131
本文介绍了动画已暂停转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动画移动带有关键帧的图像的 background-position ,这很好。



虽然,当用户点击一个按钮,我想暂停背景的动画,但有一个过渡,减慢,然后停止 background-position 移动。 / p>

我搜索过类似的东西,但我没有找到任何东西,所以我想知道你们中间有没有一个想法我怎么能做到这一点?



感谢。

解决方案

使用CSS动画只能使用一个元素时,您无法实现此目的,它们如下所示:




  • 动画的播放状态更改为暂停是立即动作。

  • 将动画应用于元素后,控制属性,直到它被删除。因此,用JS更改 background-position 也没有效果(即使它实际上已暂停)。


    W3C规范



    CSS动画会影响计算属性值。在执行动画期间,属性的计算值由动画控制。这将覆盖正常样式系统中指定的值。


    在以下代码段中可以看到一个示例。除了 animation-play-state:paused ,切换的类也会为 background-position (重要),但它对元素绝对没有影响。 JS的注释部分是我试图以较慢的速度产生渐进停止,但它只是不工作。



      var el = document.getElementsByTagName('div')[0]; var btn = document.getElementById('stop'); var i = 0,bgPosX,interval,state ='running'; btn.addEventListener 'pause'; 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 { 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;背景图像:线性梯度(右,红色25%,蓝色25%,蓝色50%,橙色50%,橙色75%,绿色75%); background-size:800px 100%; animation-name:animate-bg-pos;动画定时功能:线性; 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%; }到{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'>停止动画< / button>  


  • 删除动画将导致元素立即回到其原始位置。它不会逐渐过渡回来。您可以阅读一下此处


  • 在同一个媒体资源上应用转换和动画在浏览器上效果不佳。它仍然导致动画完全控制,并使转换无用。阅读更多这里

  • 最后,即使你以某种方式获取动画的删除,并使用JS慢慢地将其转换为中间状态,这将不会像暂停行为。原因是因为当您重新应用动画时,它将再次从第一帧开始,而不是从第一帧开始。



考虑所有这一切,你必须重写你的整个动画使用jQuery或JavaScript,如果你必须得到所需的行为。在下面的代码段中提供了一个非常粗略的实现,其中定时器和 background-position 的不断变化。



  / *初始变量声明* / 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); / *切换按钮监听器* / btn.addEventListener('click',function(){running =!running; // toggle state if(!running){i = 0; currPos = parseInt(el.style.backgroundPositionX 。* / pauseInterval = setInterval(function(){slowPause(currPos); / *调用慢暂停功能* / pauseInterval() };} else {i = 0; currPos = parseInt(el.style.backgroundPositionX.replace('px',''),10); clearInterval(pauseInterval); / *为更安全的一边,停止暂停动画的计时器* / runningInterval = setInterval(function(){anim(currPos); / *调用正常的动画的函数* /},10); }}); / *当切换被点击时缓慢地暂停* / function slowPause(currPosX){el.style.backgroundPosition =(currPosX +(i * .025))%bgSize +'px 0%'; i + = 10; if(i> = 1000){/ * end animation after somethingtime * / clearInterval(pauseInterval); i = 0; } / * increment bg position at each interval * / function anim(currPosX){el.style.backgroundPosition =(currPosX +(i * .25))%bgSize +'px 0%'; i + = 10;} / *加载时启动动画* / runningInterval = setInterval(function(){anim(currPos);},10);  

snippet-code-css lang-css prettyprint-override> .animated-bg-pos {height:100px; width:200px;背景图像:线性梯度(右,红色25%,蓝色25%,蓝色50%,橙色50%,橙色75%,绿色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'>切换动画状态< / button>  



请注意:上述代码段只是一个粗略的实现,以提供一个想法。






如果你不是一个JS专家,没有在添加额外的包装元素周围的动画的一个问题,那么你可以利用在 vals'answer Here



  var el = document.getElementsByTagName('div') [1]; var btn = document.getElementById('stop'); btn.addEventListener('click',function(){el.classList.toggle('paused');});  / pre> 

  .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;背景图像:线性梯度(右,红色25%,蓝色25%,蓝色50%,橙色50%,橙色75%,绿色75%); background-size:800px 100%;动画:animate-bg-pos 4s线性无限; transition:transform 1s ease-out;}。paused {animation-play-state:paused; transform:translateX(40px);} @ keyframes animate-bg-pos {from {background-position:0px 0%; }到{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>  



注意:上述方法的所有积分都将用于vals。我只是调整了他的方法,使这个答案更完整。


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:

  • 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: 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.

  • 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 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.

这篇关于动画已暂停转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆