动画和过渡的组合无法正常工作

IT技术 javascript css css-transitions css-animations css-transforms
2021-03-16 07:36:12

我一直在尝试放置一些基本的 CSS3 动画。目标是在按钮的单击事件上切换一个类,并根据添加的类为 div 设置动画。该代码对于 Firefox 中的第一次切换完美运行,但对于 Chrome 等其他浏览器以及 Firefox 中的下一次迭代,转换在眨眼间切换。请帮我弄清楚出了什么问题。

片段:

$('button').click(function() {
  $('div').toggleClass('clicked');
});
div {
  background-color: #ccc;
  height: 100px;
  width: 100px;
  transition-property: top, left;
  transition-duration: 1s;
  transition-timing-function: linear;
  position: relative;
  top: 0;
  left: 0;
}
.clicked {
  animation-name: clicked;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes clicked {
  0% {
    top: 0;
    left: 0;
  }
  100% {
    top: 100px;
    left: 100px;
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button">Click Me!</button>
<div></div>

我也在这里准备了一个小提琴

2个回答

这是 Chrome 的一种已知行为。Firefox 似乎确实能够通过过渡顺利处理动画的移除,但 Chrome 不会这样做。我也曾在此线程中更早地看到过这种行为

为什么在 Chrome 中删除动画不能与过渡一起使用?

虽然我无法对发生这种情况的原因提供 100% 万无一失的解释,但我们可以根据这篇关于 Chrome 中加速渲染的 HTML5Rocks 文章这篇关于 Chrome 中 GPU 加速合成的文章对其进行一定程度的解码

似乎发生的是该元素获得了自己的渲染层,因为它在其上设置了显式位置属性。当图层(或其中的一部分)因动画而失效时,Chrome 只会重新绘制受更改影响的图层。当您打开 Chrome 开发者控制台时,打开“Show Paint Rects”选项,您会看到当动画发生时,Chrome 只绘制动画的实际元素。

然而,在动画的开始和结束时,整个页面正在发生重绘,这会立即将元素放回其原始位置,从而覆盖过渡行为。

$('button').click(function(){
  $('div').toggleClass('clicked');
});
div{
  background-color: #ccc;
  height: 100px;
  width: 100px;
  transition-property: top, left;
  transition-duration: 1s;
  transition-timing-function: linear;
  position: relative;
  top: 0;
  left: 0;
}
.clicked{
  animation-name: clicked;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes clicked{
  0% {top: 0; left: 0;}
  100% {top: 100px; left: 100px;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button">Click Me!</button>
<div></div>


解决办法是什么?

由于您的运动实际上是从一个位置到另一个位置的线性运动,因此您无需任何动画即可实现。我们需要做的就是使用translate变换并将元素移动所需的编号。打开类时的像素数。由于通过另一个选择器分配给元素的转换,移位将以线性方式发生。当 class 被关闭时,由于元素上的转换,元素再次以线性方式返回到其原始位置。

$('button').click(function() {
  $('div').toggleClass('clicked');
});
div {
  background-color: #ccc;
  height: 100px;
  width: 100px;
  transition-property: transform;
  transition-duration: 1s;
  transition-timing-function: linear;
  position: relative;
  top: 0;
  left: 0;
}
.clicked {
  transform: translate(100px, 100px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<button type="button">Click Me!</button>
<div></div>

这是预期的行为。您需要使用两个单独的动画或仅使用过渡。

过渡是一种动画,只是在两个不同状态之间执行的动画,即开始状态和结束状态。就像抽屉菜单一样,开始状态可以是打开的,结束状态可以是关闭的,反之亦然。

如果您想执行一些不特别涉及开始状态和结束状态的操作,或者您需要对过渡中的关键帧进行更精细的控制,那么您必须使用动画。

这是使用过渡为元素设置动画的方法:

$('button').click(function() {
  $('div').toggleClass('clicked');
});
div {
  background-color: #ccc;
  height: 100px;
  width: 100px;
  transition-property: top, left;
  transition-duration: 1s;
  transition-timing-function: linear;
  position: relative;
  top: 0;
  left: 0;
}
.clicked {
  top: 100px;
  left: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button">Click Me!</button>
<div></div>

@halfzebra:谢谢你的回答。我希望我能接受这两个答案!
2021-05-03 07:36:12
抱歉,伙计在添加我的答案之前没有看到您的答案弹出窗口。+1 对您的方法,因为它也是实现它的正确方法。
2021-05-12 07:36:12