【问题标题】:Animation paused with transition动画因过渡而暂停
【发布时间】:2016-03-27 01:20:06
【问题描述】:

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

虽然,当用户单击按钮时,我想暂停背景动画,但有一个过渡,放慢速度然后停止 background-position 移动。

我搜索了类似的东西,但我没有找到任何东西,所以我想知道你们中是否有人知道我该怎么做?

谢谢。

【问题讨论】:

  • 发布您正在使用的代码,看看我是否可以复制它。如果您无法使用我提供的代码使其工作
  • 我认为这个答案可以帮助你stackoverflow.com/a/29682311/1926369

标签: html css css-animations


【解决方案1】:

没有。您无法通过 CSS 动画仅使用一个元素来实现这一点,原因如下:

  • 动画的播放状态更改为paused 是一个即时操作。
  • 在元素上应用动画后,它会控制该属性,直到将其移除。因此,用 JS 更改 background-position 也将没有效果(即使它实际上已暂停)。

    来自W3C Spec

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

    可以在下面的 sn-p 中看到一个示例。与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('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>
  • 移除动画将导致元素立即恢复到其原始位置。它不会逐渐过渡回来。你可以阅读一下here

  • 在同一属性上应用过渡和动画在浏览器中效果不佳。它仍然会导致动画完全控制并使过渡无用。阅读更多here
  • 最后,即使您以某种方式移除动画并使用 JS 将其缓慢转换到中间状态,这也不会类似于“暂停”行为。原因是当您重新应用动画时,它会再次从第一帧开始,而不是从您停止的位置开始。

考虑到这一切,如果您必须获得所需的行为,则必须使用 jQuery 或 JavaScript 重写整个动画。下面的 sn-p 中提供了一个非常粗略的实现,其中包含计时器和 background-position 的不断变化。

/* 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>

注意:上面的sn-p只是一个粗略的实现,给出一个思路。我不是JS高手,感觉sn-p中使用的JS可以优化很多。


如果您在正在动画的元素周围添加额外的包装元素没有问题,那么您可以使用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>

注意:上述方法的所有功劳都归于 vals。我只是调整了他的方法以使这个答案更完整。

【讨论】:

  • 可以实现,但是要使用几个元素。您解释的所有问题都是绝对正确的,但仅适用于尝试在单个元素中解决它(我并不是说这是最好的方法......只是有可能。)请参阅我上面的评论.
  • 有趣的@vals。我可以发誓我尝试了完全相同的东西,但在这里没有用。我要再试一次。
  • 它工作得非常出色@vals。我想我一定犯了一些错误。非常感谢您的建议/链接。您介意我在此答案中根据您的答案(当然还链接到您的原始答案)在 sn-p 中进行编辑吗?
  • 我当然不介意。随心所欲地为所欲为
  • 再次感谢@vals。如果我的答案与另一个线程中的信息完全相同,我会删除我的答案,但我觉得我的原始观点至少可以帮助未来的用户理解为什么不能使用单个元素。我想知道我是否应该要求一个模组将这个答案合并到那个答案中。
【解决方案2】:

为背景位置创建一个带有 CSS 过渡的类,当单击按钮时,添加该类并同时删除您的动画类。确保在这两种情况下使用相同的单位(像素、百分比...)。

【讨论】:

  • 这就是我尝试过的,但它不起作用。我将类添加到暂停动画并创建过渡的元素,然后我使用 jQuery 将背景位置添加到元素,但它不想过渡并完全停止......
  • 不,这种方法行不通,因为一旦你删除动画,元素会迅速回到原来的位置。看看这个答案 - stackoverflow.com/questions/32142484/…。 Firefox 也只是偶尔优雅地处理它(比如第一次或类似的东西),而不是总是。
  • @Shomz:我正在尝试所有技巧,看看是否可以做些什么。到目前为止不好,我认为即使 JS 解决方案在这种情况下也不起作用,但在添加答案之前要绝对确保它。只是一个不行,做不到也没多大用处。
  • 好吧,我想到的一件事是将关键帧重写为过渡并使用超时,但如果我们有原始代码会很有帮助。
  • @Shomz:我最终添加了一个单独的答案,但它仍然是 no :(
【解决方案3】:

您可以通过在单击按钮后使用 java 脚本删除和添加新类来实现它。

类似的东西。基本上只需使用 new 创建一个新的 css 类,它设置动画运行的特定时间。

例如,如果您正在运行的动画无限期地运行,则只需创建一个具有相似值但具有确定时间(如 2s 或 4s 等)的 new_class。在这些 4s 之后,动画应该停止。

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

});

【讨论】:

    猜你喜欢
    • 2015-07-05
    • 2015-02-09
    • 1970-01-01
    • 2017-08-23
    • 2014-05-27
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多