反转CSS动画 [英] Reverse a CSS animation

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

问题描述

我这样做: http://codepen.io/yayoni/pen/pgXoWY



我想反转动画,当我点击小按钮,但我做的不工作,我不明白为什么。



  function anim(){var div = document.getElementById('fab'); div.className =anim;} function animrev(){var div = document.getElementById('fab'); div.className =animrev;}  

  {height:100%; width:100%;}#content {height:100%; width:100%;显示:flex; align-items:center; justify-content:center;}#fab {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24);} anim {animation-name:example; animation-duration:1s; animation-fill-mode:forward;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; }} @ keyframes exampleux {100%{background-color:red; left:0px; top:0px; }}。animrev {animation-name:exampleux; animation-duration:1s; animation-fill-mode:forward;}  

 < div id =content> < button onclick =anim()id =fab> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   

有关详情,请参阅 CodePen

解决方案

如果是一个简单的颜色变化,我还建议CSS转换,如马丁的回答,但正如您解释的那样,这更复杂, Osama8DZ的回答是你最好的解决方案。但这不会回答你的问题,它说明了以下(重点是我的):


动画,当我点击小按钮,但我做了不工作和我不明白为什么


原因:



当您点击导致反向动画触发的按钮时,类名称发生变化,因此原始动画替换使用反转动画。这实际上是两个步骤 - 第一是删除原始动画,第二是添加相反。



每当元素上存在的动画被删除,元素立即捕捉到它的原始状态(即动画之前的状态)。这里的元素有红色背景的原始状态。因此,元素会立即获得红色背景,然后反转动画没有视觉效果,因为它是从红色背景到红色背景的动画



您可以在下面的代码段中看到我的意思。我向元素的原始状态添加了左上边距,并在向前动画期间对其进行了更改。一旦执行反向按钮点击,形状立即回到原始状态,然后应用反向动画内提供的左上边距。



  var div = document.getElementById('fab'); function anim(){div.className =anim;} function animrev(){div.className =animrev code> 

  html,body {height:100%; width:100%;}#content {height:100%;} width:100%;显示:flex; align-items:center; justify-content:center;}#fab {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24); / *添加这些演示* / margin-left:20px; margin-top:10px;}。anim {animation-name:example; animation-duration:1s; animation-fill-mode:forward;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; / *添加这些演示* / margin-left:40px; margin-top:20px; }} @ keyframes exampleux {100%{background-color:red; left:0px; top:0px; / *添加这些演示* / margin-left:30px; margin-top:15px; }}。animrev {animation-name:exampleux;动画持续时间:1s; animation-fill-mode:forward;}  

 < div id =content> < button onclick =anim()id =fab> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   




解决方案:



简单而最好的解决方案将是 Osama8DZ的回答中提供的解决方案,因为它使它看起来好像原始元素从不跳回到其原始状态。我不会进一步详细说明,因为它看起来像我复制他的答案(或)剽窃它。



但是,我要突出一些情况






情况1:当动画有延迟 - 当两个动画(或)只有相反的动画被延迟时,您仍然可以看到它回到原始状态,然后运行动画。下面的代码段显示了操作中的问题。



  var div = document.getElementById('fab'); function anim {div.className =anim;} function animrev(){div.className =animrev;}  

  html,body {height:100%; width:100%;}#content {height:100%; width:100%;显示:flex; align-items:center; justify-content:center;}#fab {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24);} anim {animation-name:example; animation-duration:1s; animation-fill-mode:向前; animation-delay:1s;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; }} @ keyframes exampleux {0%{/ *您需要添加此* / background-color:green; left:0px; top:0px; } 100%{background-color:red; left:0px; top:0px; }}。animrev {animation-name:exampleux; animation-duration:1s; animation-fill-mode:向前; animation-delay:1s;}  

 < div id = content> < button onclick =anim()id =fab> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   

如何解决?这是因为动画会持续保持其原始状态,直到延迟时间过去,因此即使反向动画中的 0%关键帧与向前动画的 100%关键帧相同,仍然回弹,然后再次动画。修复此问题的方法是将 animation-fill-mode 设置为两者(这意味着, code>向前向后),而不是转发。这使得元素在延迟期间也保持 0%关键帧的状态(由于向后)并保持即使在动画结束(由于转发)之后 100%关键帧的状态。



 

  html, body {height:100%; width:100%;}#content {height:100%; width:100%;显示:flex; align-items:center; justify-content:center;}#fab {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24);} anim {animation-name:example; animation-duration:1s; animation-fill-mode:both; animation-delay:1s;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; }} @ keyframes exampleux {0%{/ *您需要添加此* / background-color:green; left:0px; top:0px; } 100%{background-color:red; left:0px; top:0px; }}。animrev {animation-name:exampleux; animation-duration:1s; animation-fill-mode:both; animation-delay:1s;}  

 < div id = content> < button onclick =anim()id =fab> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   




情况2:如果反向动画对多个元素是通用的,动画是不同的,如下面的代码段。在下面的代码段中,第一个元素的前向动画将背景从红色更改为绿色,而第二个元素将其从 red blue ,但是反向动画应该都设置为 red 。在这种情况下,我们不能将反向动画的 0%关键帧设置为正向动画的 100%



  var div = document.getElementById('fab'); var div2 = document.getElementById('fab3'); function anim(){div.className =anim;} function animAlt(){div2.className =anim-alt;} function animrev(){div.className =animrev ; div2.className =animrev;}  

  {height:100%; width:100%;}#content {height:100%; width:100%;显示:flex; align-items:center; justify-content:center;}#fab,#fab3 {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24);} anim {animation-name:example; animation-duration:1s; animation-fill-mode:forward;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; }}。anim-alt {animation-name:example2; animation-duration:1s; animation-fill-mode:forward;} @ keyframes example2 {100%{background-color:blue; left:0px; top:0px; }} @ keyframes exampleux {0%{/ *您需要添加此* / background-color:green; left:0px; top:0px; } 100%{background-color:red; left:0px; top:0px; }}。animrev {animation-name:exampleux; animation-duration:1s; animation-fill-mode:向前; }  

 < div id =content> < button onclick =anim()id =fab> +< / button> < button onclick =animAlt()id =fab3> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   

如何解决?对于这种情况,没有纯CSS解决方案(除非您切换到使用转换)。但是,有一个解决方法,即通过内联样式将原始动画的最后一个关键帧的样式添加到元素,直到结束。这意味着我们正在模仿没有回到其原始状态的元素的效果。



  var div = document .getElementById('fab'); var div2 = document.getElementById('fab3'); function anim(){div.className =anim;} function animAlt(){div2.className =anim-alt;} function animrev(){div.className =animrev; div.className =animrev;} div.addEventListener('animationend',function(e){if(e.animationName ==example){/ *表示正向动画已结束* / this.style.backgroundColor = 'green'; this.style.marginLeft ='40px'; this.style.marginTop ='20px';} else this.style = null;})div2.addEventListener('animationend',function(e){if .animationName ==example2){/ *表示前向动画已结束* / this.style.backgroundColor ='blue'; this.style.marginLeft ='40px'; this.style.marginTop ='20px';} else this.style = null;}) 

  {height:100%; width:100%;}#content {height:100%; width:100%;显示:flex; align-items:center; justify-content:center;}#fab,#fab3 {margin-right:30px;颜色:白色; font-size:45px;轮廓:0; border:0; height:150px; width:150px; border-radius:75px; text-align:center; background-color:red; box-shadow:0 1px 3px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24); margin-left:20px; margin-top:10px; } .anim {animation-name:example; animation-duration:1s; animation-fill-mode:forward;} @ keyframes示例{100%{background-color:green; left:0px; top:0px; margin-left:40px; margin-top:20px; }}。anim-alt {animation-name:example2; animation-duration:1s; animation-fill-mode:forward;} @ keyframes example2 {100%{background-color:blue; left:0px; top:0px; margin-left:40px; margin-top:20px; }} @ keyframes exampleux {100%{background-color:red; left:0px; top:0px; margin-left:20px; margin-top:10px; }}。animrev {animation-name:exampleux; animation-duration:1s; animation-fill-mode:向前; }  

 < div id =content> < button onclick =anim()id =fab> +< / button> < button onclick =animAlt()id =fab3> +< / button> < button onclick =animrev()id =fab2> +< / button>< / div>   

请注意:我们不应该保留内置样式,因为这会导致原始动画在第二次点击时出现问题。因此,我们必须监听动画的结束事件并删除内联样式(如果有)。 animationend 仍然需要在几个版本的浏览器前缀,但我会离开这部分给你。



我希望所有以上已经为您提供了您的代码为什么不(似乎)工作,如何解决各种情况下的完整解释。


I did this: http://codepen.io/yayoni/pen/pgXoWY

And I want to reverse the animation when I click on the small button but what I did doesnt work and I don't understand why.

function anim() {
  var div = document.getElementById('fab');
  div.className = "anim";
}

function animrev() {
  var div = document.getElementById('fab');
  div.className = "animrev";
}

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
  }
}
@keyframes exampleux {
  100% {
    background-color: red;
    left: 0px;
    top: 0px;
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>

See CodePen for more details

解决方案

If it were a simple color change, I would've also recommended CSS transitions like in Martin's answer but as you've explained that it is something more complex, Osama8DZ's answer is your best solution. But that doesn't give an answer to your question, which states the following (emphasis is mine):

And I want to reverse the animation when I click on the small button but what I did doesnt work and I don't understand why.

Reason:

When you click on the button which causes the reverse animation to trigger, the class name changes and so the original animation is replaced with the reverse animation. This is actually two steps - first is removal of the original animation and second is addition of the reverse.

Whenever an animation that exists on an element is removed, the element immediately snaps to what was its original state (which is, the one before the animation). Here the element had red background in its original state. Thus the element immediately gets a red background and then the reverse animation has no visual effect because it is animating from a red background to a red background.

You can see a sample of what I mean in the below snippet. I added a left and top margin to the original state of the element and changed it during the forward animation. As soon as the reverse button click is performed, the shape immediately goes back to original state and then applies the left, top margins provided within the reverse animation.

var div = document.getElementById('fab');

function anim() {
  div.className = "anim";
}

function animrev() {
  div.className = "animrev";
}

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  
  /* added these for demo */
  margin-left: 20px;
  margin-top: 10px;
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
    
    /* added these for demo */
    margin-left: 40px;
    margin-top: 20px;
  }
}
@keyframes exampleux {
  100% {
    background-color: red;
    left: 0px;
    top: 0px;

    /* added these for demo */
    margin-left: 30px;
    margin-top: 15px;    
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>


Solution:

The simple and best solution would be the one provided in Osama8DZ's answer as it makes it look as though the original element never snapped back to its original state. I am not going to detail that further because it would look like I am copying his answer (or) plagiarizing it.

However, I am going to highlight a few cases where it doesn't work and how to fix them.


Case 1: When the animation has a delay - When either both the animations (or) only the reverse is delayed, you will still be able to see it snap back to original state before running the animation. Below snippet shows the problem in action.

var div = document.getElementById('fab');

function anim() {
  div.className = "anim";
}

function animrev() {
  div.className = "animrev";
}

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: forwards;
  animation-delay: 1s;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
  }
}
@keyframes exampleux {
  0% {
    /* You need to add this */
    background-color: green;
    left: 0px;
    top: 0px;  
  }
  100% {
    background-color: red;
    left: 0px;
    top: 0px;
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: forwards;
  animation-delay: 1s;
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>

How to fix it? The reason for this is because the animation would continue to hold its original state until the delay time is elapsed and so even though the 0% keyframe within the reverse animation is the same as 100% keyframe of forward animation, the element will still snap back and then animate again. Fix for this is to set animation-fill-mode as both (which means, to have the effect of both forwards and backwards) instead of forwards. This makes the element hold the state as at 0% keyframe during the delay period also (due to backwards) and hold the state as at 100% keyframe even after animation has ended (due to forwards).

var div = document.getElementById('fab');

function anim() {
  div.className = "anim";
}

function animrev() {
  div.className = "animrev";
}

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: both;
  animation-delay: 1s;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
  }
}
@keyframes exampleux {
  0% {
    /* You need to add this */
    background-color: green;
    left: 0px;
    top: 0px;  
  }
  100% {
    background-color: red;
    left: 0px;
    top: 0px;
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: both;
  animation-delay: 1s;
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>


Case 2: What if the reverse animation is common for more than one element but forward animation is different like in the below snippet. In the snippet below, the forward animation of first element changes background from red to green whereas the second element changes it from red to blue but the reverse animation should set both back to red. In such scenario we cannot set the 0% keyframe of reverse animation as the 100% of the forward animation because the end state is different for the two forward animations.

var div = document.getElementById('fab');
var div2 = document.getElementById('fab3');

function anim() {
  div.className = "anim";
}
function animAlt() {  
  div2.className = "anim-alt";
}

function animrev() {
  div.className = "animrev";
  div2.className = "animrev";
}

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab, #fab3 {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
  }
}
.anim-alt {
  animation-name: example2;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example2 {
  100% {
    background-color: blue;
    left: 0px;
    top: 0px;
  }
}

@keyframes exampleux {
  0% {
    /* You need to add this */
    background-color: green;
    left: 0px;
    top: 0px;  
  }
  100% {
    background-color: red;
    left: 0px;
    top: 0px;
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: forwards;  
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animAlt()" id="fab3">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>

How to fix it? There are no pure CSS solutions for this case (unless you switch to using transitions). However there is a workaround, which is to add the styles from last keyframe of the original animation via inline styles to the element right after it has ended. This means that we are mimicking the effect of the element not having snapped back to its original state.

var div = document.getElementById('fab');
var div2 = document.getElementById('fab3');

function anim() {
  div.className = "anim";
}
function animAlt() {
  div2.className = "anim-alt";
}

function animrev() {
  div.className = "animrev";
  div2.className = "animrev";
}

div.addEventListener('animationend', function(e) {
  if (e.animationName == "example") { /* meaning the forward animation has ended */
    this.style.backgroundColor = 'green';
    this.style.marginLeft = '40px';
    this.style.marginTop = '20px';
  }
  else
    this.style = null;
})
div2.addEventListener('animationend', function(e) {
  if (e.animationName == "example2") { /* meaning the forward animation has ended */
    this.style.backgroundColor = 'blue';
    this.style.marginLeft = '40px';
    this.style.marginTop = '20px';
  }  
  else
    this.style = null;
})

html,
body {
  height: 100%;
  width: 100%;
}
#content {
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
#fab, #fab3 {
  margin-right: 30px;
  color: white;
  font-size: 45px;
  outline: 0;
  border: 0;
  height: 150px;
  width: 150px;
  border-radius: 75px;
  text-align: center;
  background-color: red;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  
  margin-left: 20px;
  margin-top: 10px;  
}
.anim {
  animation-name: example;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example {
  100% {
    background-color: green;
    left: 0px;
    top: 0px;
    
    margin-left: 40px;
    margin-top: 20px;    
  }
}
.anim-alt {
  animation-name: example2;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
@keyframes example2 {
  100% {
    background-color: blue;
    left: 0px;
    top: 0px;
    
    margin-left: 40px;
    margin-top: 20px;
  }
}

@keyframes exampleux {
  100% {
    background-color: red;
    left: 0px;
    top: 0px;
    
    margin-left: 20px;
    margin-top: 10px;
  }
}
.animrev {
  animation-name: exampleux;
  animation-duration: 1s;
  animation-fill-mode: forwards;  
}

<div id="content">
  <button onclick="anim()" id="fab">+</button>
  <button onclick="animAlt()" id="fab3">+</button>
  <button onclick="animrev()" id="fab2">+</button>
</div>

Note: We should not leave the inline styles as-is because that would cause the original animation to have problems when clicked for a second time. So, we have to listen to the animation's end event and remove the inline styles (if any). The animationend still requires browser prefixing in a few versions but I would leave that part to you.

I hope all the above have provided you a full explanation of why your code does not (seem to) work, how to fix for various scenarios.

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

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