如何在 CSS 宽度变化时实现流畅的 CSS 动画?
How to achieve smooth CSS animation on CSS width change?
我正在制作自己的进度条,它将在 5 分钟到 1 秒的不同时间段内填满。我的想法是:
- 我有一个栏,其 CSS 宽度设置为 0%,每隔 x 秒
- 然后我使用 JS 将条形宽度增加 1%。
它是这样工作的:https://jsfiddle.net/dnh4y39c/
这种方法存在一些问题:
动画仅在 <2 秒内流畅(100 次间隔 20 毫秒),
除此之外,它显然不够平滑,请参阅:
https://jsfiddle.net/dnh4y39c/1/ ,
我可以用 CSS 转换来解决这个问题,但它完全崩溃了
计时,如果我在栏上设置 transition: all 0.5s;
那么它就可以工作
在更长的时间内非常好,但它完全坏了更快
负载,例如。进度条应该在 1 秒内完成,但它会停止
持续 0.5 秒,然后一次全部设置 100% 动画,请参阅:
https://jsfiddle.net/dnh4y39c/1/
我想知道我是否应该 fiddle 宽度或者只是移动到 canvas?我不知道 canvas 有那么好,但我想它可能性能更高并且占用更少的资源?我的应用程序中可能有多个进度条,因为我需要单独加载所有模块(因此没有一个简单的加载器,但在某些地方甚至可能超过 50 个 - 我知道,这很疯狂,但我只是在关注文档)。
感谢任何意见:)
需要考虑的几件事是:
- 避免使用
setInterval()
,如果间隔回调的执行时间长于间隔本身的持续时间,它会产生 "jumpy" 动画行为。如果需要帧间延迟,请改为使用 setTimeout()
- 考虑使用
window.requestAnimationFrame()
更新进度条的动画。使用 window.requestAnimationFrame()
可确保您的进度条的更新与浏览器 repaint/redraw 周期 同步
您的代码的更新版本,将这两个想法考虑在内,可能如下所示:
function interation(element, iterationDuration, i) {
window.requestAnimationFrame(function() {
/*
Update the width and transition duration of the element for this iteration
*/
element.style.width = `${i}%`;
element.style.transitionDuration = `${iterationDuration}ms`;
/*
Increment/calculate next percentage value for progress bar
*/
const next = (i === undefined ? 0 : i) + 1;
if (next <= 100) {
/*
Pass element, timeout, and next value through as arguments
to next interation() call
*/
setTimeout(interation, iterationDuration, element, iterationDuration, next);
}
})
}
interation(document.querySelector(".progress__bar"), 20);
// interation(document.querySelector(".progress__bar"), 2000); Long interval
// interation(document.querySelector(".progress__bar"), 20); Short interval
* {
box-sizing: border-box;
}
.progress__bar {
transition: width linear;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: 4px;
background: #f00;
}
<div class="item">
<div class="item__progress">
<div class="progress__bar" style="width: 0%;"></div>
</div>
</div>
我正在制作自己的进度条,它将在 5 分钟到 1 秒的不同时间段内填满。我的想法是:
- 我有一个栏,其 CSS 宽度设置为 0%,每隔 x 秒
- 然后我使用 JS 将条形宽度增加 1%。
它是这样工作的:https://jsfiddle.net/dnh4y39c/
这种方法存在一些问题:
动画仅在 <2 秒内流畅(100 次间隔 20 毫秒), 除此之外,它显然不够平滑,请参阅: https://jsfiddle.net/dnh4y39c/1/ ,
我可以用 CSS 转换来解决这个问题,但它完全崩溃了 计时,如果我在栏上设置
transition: all 0.5s;
那么它就可以工作 在更长的时间内非常好,但它完全坏了更快 负载,例如。进度条应该在 1 秒内完成,但它会停止 持续 0.5 秒,然后一次全部设置 100% 动画,请参阅: https://jsfiddle.net/dnh4y39c/1/
我想知道我是否应该 fiddle 宽度或者只是移动到 canvas?我不知道 canvas 有那么好,但我想它可能性能更高并且占用更少的资源?我的应用程序中可能有多个进度条,因为我需要单独加载所有模块(因此没有一个简单的加载器,但在某些地方甚至可能超过 50 个 - 我知道,这很疯狂,但我只是在关注文档)。
感谢任何意见:)
需要考虑的几件事是:
- 避免使用
setInterval()
,如果间隔回调的执行时间长于间隔本身的持续时间,它会产生 "jumpy" 动画行为。如果需要帧间延迟,请改为使用setTimeout()
- 考虑使用
window.requestAnimationFrame()
更新进度条的动画。使用window.requestAnimationFrame()
可确保您的进度条的更新与浏览器 repaint/redraw 周期 同步
您的代码的更新版本,将这两个想法考虑在内,可能如下所示:
function interation(element, iterationDuration, i) {
window.requestAnimationFrame(function() {
/*
Update the width and transition duration of the element for this iteration
*/
element.style.width = `${i}%`;
element.style.transitionDuration = `${iterationDuration}ms`;
/*
Increment/calculate next percentage value for progress bar
*/
const next = (i === undefined ? 0 : i) + 1;
if (next <= 100) {
/*
Pass element, timeout, and next value through as arguments
to next interation() call
*/
setTimeout(interation, iterationDuration, element, iterationDuration, next);
}
})
}
interation(document.querySelector(".progress__bar"), 20);
// interation(document.querySelector(".progress__bar"), 2000); Long interval
// interation(document.querySelector(".progress__bar"), 20); Short interval
* {
box-sizing: border-box;
}
.progress__bar {
transition: width linear;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: 4px;
background: #f00;
}
<div class="item">
<div class="item__progress">
<div class="progress__bar" style="width: 0%;"></div>
</div>
</div>