【问题标题】:CSS percentage of transition (for progress bar)CSS 过渡百分比(用于进度条)
【发布时间】:2021-06-13 21:20:18
【问题描述】:

我正在尝试制作一个带有动画的“进度条”,可以改变进度条的背景颜色。

该条应在 0% 处以红色开始,随着它在元素上前进,它会在 100% 处变为绿色。我已经 100% 工作了(不,颜色不是很好,但这是未来的问题)......

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>

问题是(例如)在 50% 时,我无法让条形图在红色和绿色之间的 50% 过渡状态“停止”。

有没有办法计算颜色为 50% 或让 CSS 在特定点停止过渡?

你可以看到如果我有一个 50% 的值会发生什么......它仍然一直到绿色但在 50% 宽度处停止,但我希望它在 50% 过渡颜色处停止(即从红色到红色和绿色的中间)...

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>

其他信息(应0stone0 的要求)在页面加载时将不知道百分比值,但将通过 AJAX 调用提供。

【问题讨论】:

标签: javascript css css-transitions


【解决方案1】:

“停止”渐变过渡可能非常困难。

请考虑另一种方法,即手动计算所需的最终颜色。将此颜色值用作transition 的目标。这样就无需“停止”过渡,因为最终颜色已经与百分比成正比。

我使用this function 根据百分比计算绿色和红色之间的渐变。

为确保栏始终可点击,我们已将 onClick 移动到 .progress div,以便我们可以以 0 宽度呈现 .bar

(更新答案,基于 cmets)

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>

(原始答案)

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>

【讨论】:

  • 我喜欢这个想法...但与其直接设置颜色,不如先解决一次,然后将其设置为过渡的最终颜色。我要演戏
  • 啊,也许您可​​以将其添加到 OP 中?开辟了更多解决方案。
  • @freefaller 不会在你的 ajax 回调上调用 getGradient(percentage/100) 来解决你的问题吗?我的意思是你只需要知道那个百分比的颜色值对吗?那么你可以随心所欲地使用它吗?因为运行过渡会引入 时间,并且只能由 polling 或一个不错的事件驱动解决方案(如果有的话)处理。
  • 是的,它不需要任何间隔处理就可以工作。所以关键是getGradient 代码。基于此,我可以将widthbackground-colour 设置为百分比的正确颜色。如果您可以修改您的问题(或者如果您愿意,我可以),那么我们很好:-)
  • 我已将我的版本添加为隐藏脚本...请随意编辑(点击小幅修改,因为栏开始时为 0%,所以你可以'不要点击它,这就是为什么我把它移到了进度)
【解决方案2】:

您可以通过获取计算的样式并将其设置为您的bar 元素(单击按钮)或当我们通过@987654324 使用轮询达到progress 元素的percentage 宽度来执行此类操作@ 像这样:-

var bar = document.getElementById("bar");
    setTimeout(function(){
      bar.style.width = "100%";
      bar.classList.add("show");
    },10);


function stopProgressAt(percentage){
let interval = setInterval(()=>{
 const progress = document.getElementById("progress");
 const width = getComputedStyle(bar).getPropertyValue('width');
if((parseInt(width) * 100)/(Math.floor(progress.offsetWidth)) >= percentage ){
pauseTransition();
setTimeout(()=>clearInterval(interval),0);
}
},0)
}


function pauseTransition(){
     const bgColor = getComputedStyle(bar).getPropertyValue('background-color');
    const width = getComputedStyle(bar).getPropertyValue('width');
     bar.style.width=width;
     bar.style.backgroundColor=bgColor;
    ;}
    
 stopProgressAt(66);   
#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>
    <button onclick="pauseTransition()">Pause</button>

【讨论】:

  • 感谢您的回答。你能告诉我这个工作是如何在一个特定的百分比值下工作的……比如 66%。这不是人们会手动停止的东西,而是会根据预定的百分比值显示的东西
  • @freefaller 通过setIntervalpercentage 变量尝试轮询机制更新了答案。
  • 感谢您的努力,但这看起来令人难以置信......它也会导致(在我的 Firefox 上)栏到达中间(尽管我建议 66% 作为示例),然后收回几个像素
  • @freefaller 你是对的,它很老套。也许animation keyframes 和pause-state 对你来说很方便。但它在 firefox 中对我来说工作正常。但是是的,在视口调整大小时,您将看不到所需的行为。需要额外的resize 事件处理程序,以使栏与进度宽度保持一致。
  • 您可以将 percentage 变量设置为 66,以防万一您错过了它。
【解决方案3】:

使用不透明的叠加层,如下所示:

setTimeout(function() {
  const hue = 120;
  const size = 0.7;
  const H = hue * size;
  const L = (size < .5 ? 1 - size : size) * 50;
  const hsl = `hsl(${H}, 100%, ${L}%)`;
  const progress = document.getElementById('progress');
  progress.style.setProperty('--size', size);
  progress.style.setProperty('--hsl', hsl);
}, 500);
#progress {
  --size: 0;
  --hsl: hsl(0, 100%, 50%);
  position: relative;
  overflow: hidden;
  width: 200px;
  height: 20px;
  border: 1px solid #888;
  background-color: var(--hsl);
  transition: background-color 1s;
}
#bar {
  width: 100%;
  height: 100%;
  background: white;
  transition: margin-left 1s;
  margin-left: calc(var(--size) * 100%);
}
&lt;div id="progress"&gt;&lt;div id="bar"&gt;&lt;/div&gt;&lt;/div&gt;

【讨论】:

    猜你喜欢
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2015-06-03
    • 2010-11-22
    相关资源
    最近更新 更多