Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS percentage of transition (for progress bar)

I'm trying to make a "progress bar" with animation that changes the background colour of the bar.

The bar should start with red at 0% and as it progresses across the element it changes to green at 100%. I've got this working for 100% (and no, the colour is not great, but that's a future problem)...

setTimeout(function(){
  var bar = document.getElementById("bar");
  bar.style.width = "100%";
  bar.classList.add("show");
},10);
#progress {
  border:1px solid #888;
  background-color:#eee;
  height:
  width:100%;
}
#bar {
  height:30px;
  background-color:red;
  width:0;
  transition: all ease 1s;
}
#bar.show {
  background-color:lightgreen;
}
<div id="progress"><div id="bar"></div></div>

The problem is that (for example) at 50% I cannot get the bar to "stop" at the 50% transition state between the red and the green.

Is there a way to either calculate the colour as it would be at 50% or get CSS to stop the transition at a particular point?

You can see what happens if I have a 50% value... where it still goes all the way to green but stops at the 50% width, but what I want it to do is stop at the 50% transition colour (i.e. going from red to mid-way between red and green)...

setTimeout(function(){
  var bar = document.getElementById("bar");
  bar.style.width = "50%";
  bar.classList.add("show");
},10);
#progress {
  border:1px solid #888;
  background-color:#eee;
  height:
  width:100%;
}
#bar {
  height:30px;
  background-color:red;
  width:0;
  transition: all ease 1s;
}
#bar.show {
  background-color:lightgreen;
}
<div id="progress"><div id="bar"></div></div>

Additional Info (as requested by 0stone0) the percentage value will not be known at the time the page is loaded, but will be provided via an AJAX call.

like image 733
freefaller Avatar asked Dec 01 '25 20:12

freefaller


1 Answers

'Stopping' a gradient transition could be quite difficult.

Please consider an alternative approach, one where you manually calculate the desired final color. Use this color value as the target for the transition. This way there's no need to 'stop' the transition, since the final colour is already proportional to the percentage.

I've used this function to calculate the gradient between green and red, based on the percentage.

To ensure the bar is always clickable, we've moved the onClick to the .progress div so we can render the .bar at 0 width.

(Updated answer, based on comments)

function load(progress, perc) {
  var bar = progress.getElementsByClassName("bar")[0];
  bar.style.width = perc.toString() + "%";
  bar.style.backgroundColor = getGradient(perc / 100);
}

function getGradient(ratio) {
  var color1 = '90ee90'; // lightgreen
  var color2 = 'FF0000'; // red
  var hex = function(x) {
    x = x.toString(16);
    return (x.length == 1) ? '0' + x : x;
  };

  var r = Math.ceil(parseInt(color1.substring(0,2), 16) * ratio + parseInt(color2.substring(0,2), 16) * (1-ratio));
  var g = Math.ceil(parseInt(color1.substring(2,4), 16) * ratio + parseInt(color2.substring(2,4), 16) * (1-ratio));
  var b = Math.ceil(parseInt(color1.substring(4,6), 16) * ratio + parseInt(color2.substring(4,6), 16) * (1-ratio));
  return '#' + hex(r) + hex(g) + hex(b);
}
.progress {
  border:1px solid #888;
  background-color:#eee;
  height:30px;
  width:100%;
}
.bar {
  height:30px;
  background-color:red;
  width:0;
  transition: all ease 1s;
}
Click to run...<br/>
<div class="progress" onclick='load(this, 25)'><div class="bar">25%</div></div>
<div class="progress" onclick='load(this, 50)'><div class="bar">50%</div></div>
<div class="progress" onclick='load(this, 75)'><div class="bar">75%</div></div>
<div class="progress" onclick='load(this, 100)'><div class="bar">100%</div></div>

(Original answer)

function load(bar, until) {
  var p = 0;
  setInterval(function() {
  
    // Clear on complete
    if (p > until) {
      clearInterval(this);
      return;
    }
    
    // Update Bar
    bar.innerHTML = p;
    bar.style.background = getGradient((p/1)/100);
    bar.style.width = p + "%";
    
    // Bump percentage 
    p++;
  }, 100);
}

function getGradient(ratio) {
    var color1 = '90ee90'; // lightgreen
    var color2 = 'FF0000'; // red
    var hex = function(x) {
        x = x.toString(16);
        return (x.length == 1) ? '0' + x : x;
    };

    var r = Math.ceil(parseInt(color1.substring(0,2), 16) * ratio + parseInt(color2.substring(0,2), 16) * (1-ratio));
    var g = Math.ceil(parseInt(color1.substring(2,4), 16) * ratio + parseInt(color2.substring(2,4), 16) * (1-ratio));
    var b = Math.ceil(parseInt(color1.substring(4,6), 16) * ratio + parseInt(color2.substring(4,6), 16) * (1-ratio));
    return '#' + hex(r) + hex(g) + hex(b);
}
.progress {
  border:1px solid #888;
  background-color:#eee;
  height: 50px;
  width:100%;
}
.bar {
  height:100%;
  width:100%;
}
<div class="progress"><div onClick='load(this, 100)' class="bar"></div></div>
<div class="progress"><div onClick='load(this, 50)'  class="bar"></div></div>
like image 166
0stone0 Avatar answered Dec 03 '25 09:12

0stone0



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!