CSS3 值频繁变化时转换过渡会卡顿(与性能无关)
CSS3 transform transition stutters when value changes frequently (not performance related)
我目前正在 HTML 和 CSS PhoneGap 项目中构建一个指南针应用程序,使用 DeviceOrientation plugin 获取指南针航向。
我创建了 a jsbin to emulate the heading change。
我遇到的问题是,当值频繁变化时(每 200 毫秒),CSS 转换会出现相当多的断断续续。
你可以通过转到我上面链接的 jsbin 并慢慢拖动滑块来增加或减小旋转度来看到这个问题,特别是当你缓慢地来回拖动滑块时。
这让我相信这不仅仅是性能或帧率问题;这很可能是由中断转换的快速值变化引起的。
请注意在实际的 PhoneGap 应用程序中,罗盘值每 200 毫秒(或其他任意时间间隔)刷新一次,而不是您在 jsbin 模拟中看到的不一致的更新间隔.
我试着调整一下过渡持续时间,none 成功了。这是我尝试过的:
- 尝试使转换持续时间比值更改间隔短 0.5 毫秒。例如。每 500 毫秒获取新值,将转换持续时间设置为 450 毫秒。不仅让我口吃,还让整个过渡明显欠缺。
- 试图使过渡持续时间比更新间隔长(出于绝望),惊讶于它的工作...一段时间然后又开始让我口吃。
- 试图使过渡持续时间与更新间隔相同,同样卡顿。
现在我的问题是:当旋转值频繁变化时,我应该如何使 CSS3 过渡平滑而不卡顿? 另外,是否切换到 JavaScript 动画缓解了这个问题,比如在值改变时暂停过渡?
解法:
用 Javascript 动画替换 CSS3 过渡。我使用 Velocity.js 作为动画。每次指南针航向值发生变化时,我首先通过执行 Velocity(compass_element, "finish")
来完成上一个动画,然后为该元素的 rotateZ
设置动画。
在 CodeMentor 上看到了您的 post。问题是每次值更改时,它 停止 当前正在发生的转换并开始另一个相同(长)持续时间的转换。如果这是快速连续完成的,它看起来并没有做很多事情,因为它试图不断地缓和并且永远不会进入过渡太远,从而导致卡顿。
您需要根据行进的距离来进行转换,而不仅仅是像您现在这样的时间。有很多方法可以做到这一点,一对夫妇如下:
- 每次值更改时,计算指针需要移动多远,并根据一些速度和缓动输入为其创建过渡。
- 每次值变化时都以对数方式逼近新目标。这意味着每 n 分之一秒,您将向目标移动大约 1/k 的距离(只要距离至少为一个像素),其中 k 是某个常数,例如 2。因此,如果您转换元素每 0.05 秒中途,它会相当快地接近目标。使用这种方法的难点在于开始时看起来还不错,我不确定它到底是如何工作的,它可能需要一些尝试。
另一个选项(我个人可能会这样做)只是让过渡持续时间更短,拖动时,0.1s 似乎效果很好。您可以将 dragstart 上的过渡持续时间更改为这个较短的值,然后将其切换回 dragstop,为点击留出更长的过渡持续时间。
我目前正在 HTML 和 CSS PhoneGap 项目中构建一个指南针应用程序,使用 DeviceOrientation plugin 获取指南针航向。
我创建了 a jsbin to emulate the heading change。
我遇到的问题是,当值频繁变化时(每 200 毫秒),CSS 转换会出现相当多的断断续续。
你可以通过转到我上面链接的 jsbin 并慢慢拖动滑块来增加或减小旋转度来看到这个问题,特别是当你缓慢地来回拖动滑块时。
这让我相信这不仅仅是性能或帧率问题;这很可能是由中断转换的快速值变化引起的。
请注意在实际的 PhoneGap 应用程序中,罗盘值每 200 毫秒(或其他任意时间间隔)刷新一次,而不是您在 jsbin 模拟中看到的不一致的更新间隔.
我试着调整一下过渡持续时间,none 成功了。这是我尝试过的:
- 尝试使转换持续时间比值更改间隔短 0.5 毫秒。例如。每 500 毫秒获取新值,将转换持续时间设置为 450 毫秒。不仅让我口吃,还让整个过渡明显欠缺。
- 试图使过渡持续时间比更新间隔长(出于绝望),惊讶于它的工作...一段时间然后又开始让我口吃。
- 试图使过渡持续时间与更新间隔相同,同样卡顿。
现在我的问题是:当旋转值频繁变化时,我应该如何使 CSS3 过渡平滑而不卡顿? 另外,是否切换到 JavaScript 动画缓解了这个问题,比如在值改变时暂停过渡?
解法:
用 Javascript 动画替换 CSS3 过渡。我使用 Velocity.js 作为动画。每次指南针航向值发生变化时,我首先通过执行 Velocity(compass_element, "finish")
来完成上一个动画,然后为该元素的 rotateZ
设置动画。
在 CodeMentor 上看到了您的 post。问题是每次值更改时,它 停止 当前正在发生的转换并开始另一个相同(长)持续时间的转换。如果这是快速连续完成的,它看起来并没有做很多事情,因为它试图不断地缓和并且永远不会进入过渡太远,从而导致卡顿。
您需要根据行进的距离来进行转换,而不仅仅是像您现在这样的时间。有很多方法可以做到这一点,一对夫妇如下:
- 每次值更改时,计算指针需要移动多远,并根据一些速度和缓动输入为其创建过渡。
- 每次值变化时都以对数方式逼近新目标。这意味着每 n 分之一秒,您将向目标移动大约 1/k 的距离(只要距离至少为一个像素),其中 k 是某个常数,例如 2。因此,如果您转换元素每 0.05 秒中途,它会相当快地接近目标。使用这种方法的难点在于开始时看起来还不错,我不确定它到底是如何工作的,它可能需要一些尝试。
另一个选项(我个人可能会这样做)只是让过渡持续时间更短,拖动时,0.1s 似乎效果很好。您可以将 dragstart 上的过渡持续时间更改为这个较短的值,然后将其切换回 dragstop,为点击留出更长的过渡持续时间。