反转 CSS 动画

2023-12-13

我这样做了: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";
}
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更多细节


如果只是简单的颜色变化,我还会推荐 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在某些版本中仍然需要浏览器前缀,但我会将这部分留给您。

我希望以上所有内容都能为您提供完整的解释,说明为什么您的代码不起作用(似乎),以及如何针对各种情况进行修复。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

反转 CSS 动画 的相关文章

  • React 不响应按键事件

    我正在尝试实现一些非常基本的按键检测 但我根本无法让它工作 我有一个裸露的组件 应该在onKeyDown事件 但控制台中没有任何内容被注销 class App extends React Component constructor prop
  • 在导航栏下方添加背景图片

    我想在导航栏下方添加背景图像 具有完整窗口大小的宽度 它不应覆盖整个页面长度 而是从导航栏菜单下方开始 一直向下直到特定的指定高度 但宽度是满的 我参考了以下内容 但仍然没有结果 在 Twitter Bootstrap 中的导航栏下方启动背
  • 有 CSS 父选择器吗?

    我该如何选择 li 元素是锚元素的直接父元素 举个例子 我的 CSS 应该是这样的 li lt a active property value 显然 有多种方法可以使用 JavaScript 实现此目的 但我希望 CSS Level 2 本
  • 在 Javascript 中动态添加事件处理程序

    我在使用 Javascript 时遇到了一个奇怪的问题 我得到的是一个特定格式的字符串 我将尝试用它创建一个表 该表每行只有一个单元格 字符串的格式为 每个单元格 行 需要显示内容 将传递给的参数onmouseover当用户将鼠标移动到显示
  • 使用 javascript 禁用按钮:FF 与 IE

    我有一排按钮 它们都会创建一个我想在新选项卡中打开的 pdf 文件 这样按钮页面就会保持在顶部 并且 pdf 会打开以进行打印 为了防止单击按钮两次 我禁用该按钮 如下所示 我使用 python
  • 为什么 JSON.stringify 对于似乎具有属性的对象返回空对象符号“{}”?

    下面的例子表明JSON stringify 返回字符串 对于 SpeechSynthesisVoice 对象 var voiceObject window speechSynthesis getVoices 0 JSON stringify
  • 覆盖函数(例如“警报”)并调用原始函数?

    我想用调用原始版本的新版本覆盖 Javascript 内置函数 类似于用调用的版本覆盖类上的方法 super有多种语言版本 我怎样才能做到这一点 例如 window alert function str do something addit
  • 获取 JSON 中的 HTML 以在 React 组件中呈现为 HTML

    试图找出如何让链接实际呈现为链接 现在 在我从 Json 文件中读取这行文本后 React 将超链接渲染为文字文本 而不将其渲染为链接 一些数据 json about John has a blog you can read a href
  • 如何在表格的 tbody/thead 部分周围创建边框?

    我正在尝试创建一个包含表格数据的页面 该页面必须显示为多个表格 然而 我有两个相互冲突的要求需要解决 每个表格周围都必须有边框 每个表格的列宽必须能够根据内容重新调整大小 但是 所有表中的列宽必须一致 即列的大小基于所有表中该列中最大的单元
  • 如果多个键是相同的 JS,则对对象中的值求和

    例如我有 5 个对象 row aa col 1 value 1 row bb col 2 value 1 row bb col 3 value 1 row aa col 1 value 1 row aa col 2 value 1 我想对值
  • 为 Meteor 数据创建编号列表

    有没有办法获取 Meteor 集合中项目的编号列表的 编号 我知道我可以在 html 中做到这一点 但我觉得如果我可以在 spacebars 中放置一些东西 那么样式会更容易 如果我可以使用更好的术语 请告诉我 像这样的东西 前 20 部电
  • div Hello div div Howdy dere pardner div div div 我明白它的作用 但为什么叫这个名字both 什么是both mean 两者的意思是 一组两件事中的每一项 左 和 右 两件事
  • 水平平滑滚动 100px

    Heyjo problem 一周以来我一直在寻找 javascript 或 jQuery 代码 以便在我的网站上实现滚动按钮 我失败的那一刻是按钮应该多次工作的时候 他的任务不是滚动到专用元素 而是应该向左滚动 例如 100px 此外 滚动
  • 如何设置在浏览器的新选项卡(_blank)中打开的pdf文件的标题

    这是我的尝试 是否在新选项卡上打开 但它总是显示test pdf如题 function titlepath path name alert path alert name document title name window open pa
  • 删除

    好的 我有一个小菜单栏 菜单内的三个元素还有更多的子菜单 但是菜单栏中的元素之间有不必要的间距 而且我创建的子菜单有不必要的背景宽度 我在代码中将其涂成白色以使读者理解 由于这种不必要的宽度 即使鼠标悬停在不可见的宽度上 在本例中为白色 本
  • 为什么 JSON 结果可以是布尔值而不是对象或数组?

    From JSON 网站 http json org JSON 建立在两种结构之上 名称 值对的集合 在各种语言中 这被实现为对象 记录 结构 字典 哈希表 键控列表或关联数组 值的有序列表 在大多数语言中 这被实现为数组 向量 列表或序列
  • 在角度控制器中监听文档事件

    如何捕获角度控制器中的事件 我有文档级事件 所以我需要在角度控制器中捕获事件 这可能吗 Update 我有独立的 js 文件来处理来自相机的一些操作 document addEventListener myCameraEvent handl
  • 使用 javascript Array reduce() 方法有什么真正的好处吗?

    reduce 方法的大多数用例都可以使用 for 循环轻松重写 对 JSPerf 的测试表明 reduce 通常会慢 60 75 具体取决于每次迭代内执行的操作 除了能够以 函数式风格 编写代码之外 还有什么真正的理由使用reduce 吗
  • 如何使用引用该键的变量来获取对象键中的值?

    我有一个对象 我可以引用密钥a如下 var obj a A b B c C console log obj a return string A 我想通过使用变量引用对象键来获取值 如下所示 var name a console log ob
  • 从顶部开始在同一水平线上显示同一行中的两个 div

    这是我的代码 floating box display inline block width 150px margin 10px border 3px solid 73AD21 after box border 3px solid red

随机推荐