如果只是简单的颜色变化,我还会推荐 CSS 过渡,如马丁的回答但正如你所解释的,这是更复杂的事情,Osama8DZ 的回答是您最好的解决方案。但这并不能回答您的问题,该问题指出以下内容(重点是我的):
当我单击小按钮时,我想反转动画,但我所做的不起作用并且我不明白为什么.
Reason:
当您单击导致反向动画触发的按钮时,类名称会发生变化,因此原始动画是replaced与反向动画。这实际上是两个步骤 - 首先是删除原始动画,第二是添加反向动画。
每当删除元素上存在的动画时,该元素会立即捕捉到其原始状态(即动画之前的状态)。此处该元素在其原始状态下具有红色背景。因此该元素立即获得红色背景,然后反向动画没有视觉效果,因为它是从红色背景到红色背景的动画.
您可以在下面的代码片段中看到我的意思的示例。我向元素的原始状态添加了左边距和上边距,并在前进动画期间更改了它。一旦执行反向按钮单击,形状立即返回到原始状态,然后应用反向动画中提供的左、上边距。
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>
解决方案:
最简单且最好的解决方案是中提供的解决方案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%;
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>
如何修复它?这样做的原因是因为动画将继续保持其原始状态,直到延迟时间过去,因此即使0%
反向动画中的关键帧与100%
向前动画的关键帧,该元素仍会快速向后移动,然后再次进行动画处理。解决这个问题的方法是设置animation-fill-mode
as both
(这意味着,具有两者的效果forwards
and backwards
) 代替forwards
。这使得元素保持如下状态0%
关键帧也在延迟期间(由于backwards
)并保持状态为100%
即使在动画结束后也可以使用关键帧(由于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:如果反向动画对于多个元素很常见,但向前动画不同(如下面的代码片段所示),该怎么办?在下面的代码片段中,第一个元素的前向动画将背景从red
to green
而第二个元素将其更改为red
to 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";
}
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>
如何修复它?对于这种情况,没有纯 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";
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:我们不应该保留内联样式,因为这会导致原始动画在第二次单击时出现问题。因此,我们必须监听动画的结束事件并删除内联样式(如果有)。这animationend
在某些版本中仍然需要浏览器前缀,但我会将这部分留给您。
我希望以上所有内容都能为您提供完整的解释,说明为什么您的代码不起作用(似乎),以及如何针对各种情况进行修复。