Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change width of element without reflow

I have a music player with an animated bar that displays the current position in the song. It is rendered with requestAnimationFrame and works by changing the width style of the div to X%, where X is the percentage of time through the current song.

This causes huge CPU use in Chrome I believe due to the constant reflow work being done each frame. What are other options I can use to eliminate reflows and reduce CPU?

Two other requirements: this web page is a web UI over a back end music server. It's not using any HTML5 media elements. As such, the page may be loaded when the song is already partially over, so the position will not always animate between 0 and 100.

The below fiddle shows up at about 30% CPU on my machine, which seems a bit high to animate a rectangle.

var pos = 0;
var s = document.getElementById('i');
f = function() {
  window.requestAnimationFrame(f);
  pos += .03;
  s.style.width = pos + '%';
}
f();
#i {
  background-color: red;
  position: absolute;
}
<div id="i">&nbsp;
</div>
like image 784
mjibson Avatar asked Dec 01 '25 20:12

mjibson


2 Answers

There are a number of ways you could make a pure CSS progress bar that won’t cause a relayout, here are a few examples:

  1. animation - http://jsbin.com/yoqabe/edit?html,css,js,output

    I think one of the most performant ways would be to use an animation to control the background position of a linear-gradient. The only downside is that you can only play/pause the animation.

  2. background-position - http://jsbin.com/veyibe/edit?html,css,js,output

    If you need the ability to update the position with JS, then I would suggest updating the background-position of a gradient and applying CSS transitions, debouncing to avoid updating too quickly.

  3. translateX: http://jsbin.com/zolurun/edit?html,js,output

    You could also use CSS transforms to slide the progress bar inside of a container, which should also avoid a repaint.

These links might also be useful:

  • List of CSS layout, paint, and composite triggers: http://csstriggers.com
  • Debounce info: https://davidwalsh.name/javascript-debounce-function
like image 62
Ted Whitehead Avatar answered Dec 04 '25 08:12

Ted Whitehead


You can consider using other CSS properties which don't require layout opearations, such as background-size.

And use CSS animations instead of requestAnimationFrame.

var bar = document.getElementById('i');
function playSong(currentTime, duration) {
  bar.style.animationDuration = duration + 's';
  bar.style.animationDelay = - currentTime + 's';
}
playSong(3, 10);
#i {
  height: 1em;
  background-image: linear-gradient(red, red);
  background-repeat: no-repeat;
  animation: bar linear;
}
@keyframes bar {
  from { background-size: 0% 100%; }
  to { background-size: 100% 100%; }
}
<div id="i"></div>
like image 38
Oriol Avatar answered Dec 04 '25 09:12

Oriol



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!