I'm working on my own progress bar which will be filling up over different periods of time from 5 minutes to 1 second. My idea for this is:
It works like this: https://jsfiddle.net/dnh4y39c/
There are a few issues with this approach:
the animation is smooth only for <2 seconds (100 intervals of 20ms), anything over that and it's visibly not smooth enough, see: https://jsfiddle.net/dnh4y39c/1/ ,
I can battle the issue with CSS transition but it totally breaks
timing, if I set transition: all 0.5s;
on the bar then it works
pretty much well for longer times but it's totally broken on faster
loads, eg. progress bar should be done in 1s but instead it stops
for 0.5s and then animates 100% all at once, see:
https://jsfiddle.net/dnh4y39c/1/
I'm wondering if I should fiddle with width or maybe just move to canvas? I don't know canvas that good but I guess it might be more performant and take up less resources? I might have multiple progress bars within my app as I'm required to load all modules separately (so no one simple loader but might be even over 50 in some places - I know, it's crazy but I'm just following the docs).
Thanks for any input :)
A couple of things to consider would be:
setInterval()
, which can produce "jumpy" animation behavior if the interval callback takes longer to execute that the duration of the interval of itself. Instead use setTimeout()
if inter-frame delays are neededwindow.requestAnimationFrame()
to update the progress bar's animation. Using window.requestAnimationFrame()
ensures that your progress bar's update is in sync with the browsers repaint/redraw cycleAn updated version of your code, that factors these two ideas in could look like this:
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>