Changing the width of a centered progress bar I am making a game in which the player has a certain amount of available boost. To show this, I am using a blue bar inside a black frame. The bar can grow and shrink at different rates as available boost goes up and down. It works well and looks nice, but it almost halves my FPS. 

The relevant snippet:



var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;

function setBoost(boostAmount) {
  boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
};

function demonstrateBoostChange() {
  currBoost -= 1;
  setBoost(currBoost);
  if (currBoost &lt; 1) {
    currBoost = maxBoost;
  }
  requestAnimationFrame(demonstrateBoostChange);
}
requestAnimationFrame(demonstrateBoostChange);
#boost-bar {
  bottom: 10px;
  position: absolute;
  right: 20%;
  left: 20%;
  height: 20px;
  border-radius: 12px;
  border-style: solid;
  border-width: 2px;
  border-color: rgb(0, 0, 0);
}

#available-boost {
  margin: 0 auto;
  height: 20px;
  width: 100%;
  text-align: center;
  font-weight: bold;
  border-radius: 10px;
  background-color: rgb(0, 225, 255);
}
&lt;div id="boost-bar"&gt;
  &lt;div id="available-boost"&gt;Boost&lt;/div&gt;
&lt;/div&gt;



(I see the slight glitch where the text moves when very little boost remains, but I can solve that later. )

The performance hit is probably not noticeable  since it is the only thing running, but I have used Chrome DevTools to see that it is the slowest part of my code. I think this is because changing the width is triggering a reflow.

How can I improve the performance of the above code?

Some considerations:


I am already using a canvas for some other things, would it be faster to just put the bar on that?
The boost can change at different rates, depending on the maxBoost.
You may put your text "Boost" in a seperate element and position it.
Check this:



var inner = document.querySelector(".inner");
var cb = function() {
  var k = 1 - Date.now() % 1500 / 1500;
  inner.style.width = (k * 100).toFixed(2) + "%";
  window.requestAnimationFrame(cb);
};
cb();
.boost {
  border: 2px solid #999;
  width: 300px;
  position: relative;
  font: 16px mono;
}

.boost .inner {
  margin: 0 auto;
  background-color: #999;
}

.boost .text {
  position: absolute;
  text-align: center;
  top: 0;
  left: 0;
  width: 100%;
}
&lt;div class="boost"&gt;
  &lt;div class="inner"&gt;&amp;nbsp;&lt;/div&gt;
  &lt;div class="text"&gt;BOOST&lt;/div&gt;
&lt;/div&gt;




Note how position: absolute; behaves inside position: relative;.



After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.

Example with CSS animations:


var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function () {
  // Animation just ended
  inner.parentNode.style = 'display:none;';
})
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';
.boost {
  border: 2px solid #999;
  width: 300px;
  position: relative;
  font: 16px mono;
}

.boost .inner {
  margin: 0 auto;
  background-color: #999;
  animation-timing-function: linear;
}

.boost .text {
  position: absolute;
  text-align: center;
  top: 0;
  left: 0;
  width: 100%;
}

@keyframes boost {
  0% { width: 100%; }
  100% { width: 0; }
}
&lt;div class="boost"&gt;
  &lt;div class="inner"&gt;&amp;nbsp;&lt;/div&gt;
  &lt;div class="text"&gt;BOOST&lt;/div&gt;
&lt;/div&gt;