仅使用 CSS 的复杂比例三元进度条设计 浏览器支持 value

我制作了一个自定义进度条,由三个单独的部分组成(一个独特的可自定义的中心部分、一个左侧部分和一个右侧部分),但是我很难正确地对齐中心块所有阶段。

首先我将使用三个图形布局显示所需的最终状态,然后我将描述当前的问题,最后我将提供我当前的解决方法 hack,这是有问题的,需要某种修复。


三种理想状态:
显示 1% 左对齐的起始状态的预期结果:

仅使用 CSS 的复杂比例三元进度条设计
      
    浏览器支持 value

50% 处中心块完美位于中间的理想结果:

仅使用 CSS 的复杂比例三元进度条设计
      
    浏览器支持 value

中心块完美停在100%右对齐的理想结束状态:

仅使用 CSS 的复杂比例三元进度条设计
      
    浏览器支持 value


body{margin: 100px; background: #CCC}

.fullbar{
    background-color: blue;
    width: 100%;
}

.progress{
    background: green;
  margin: 10px 0 0 0;
    text-align: right;
    padding: 0 0px 1px 0px;
    line-height: 5px;
}

.number{
  background: inherit;
  color: #FFF;
    padding: 4px;
    padding: 0 2px 1px 3px;
 
}
<div class="fullbar">
<div class="progress" style="width:50%">
    <div class="number">50%</div>
</div>
</div>


问题
当状态为 50% 时,中心块应在中间完美水平对齐。 然而事实并非如此。行尾居中,而不是包含实际数字“50%”的 div。

仅使用 CSS 的复杂比例三元进度条设计
      
    浏览器支持 value


附注。出于未知原因,中心块的主体未在代码视图中正确呈现。 也许我大量的 css 重置使我的进度条看起来与这里的裸代码不同。 但它是关于类名 number 的 div 需要正确居中,目前还没有。


我的 Hacky 解决方案,工作不正常且不优雅
我尝试用 width:112% 包裹中心部分作为对进度条的一种黑客攻击,使中心块完美居中,如下所示:

<div class="fullbar">
  <div style="width:112%">
    <div class="progress" style="width:50%">
      <div class="number">50%</div>
    </div>
  </div>
</div>

然而,虽然这确实使 50% 看起来完全水平居中,但最终状态 100% 现在被推到右侧超出 div 边界,使解决方案不正确且无法使用。


主要问题和第一个悬赏(50 分)
很高兴找到另一种 CSS(flex 或 calc)解决方案,其中所有三个理想状态(参见上面三张图片)完美对齐,其中状态适合开始状态、结束状态以及“成比例”之间的所有状态。


奖励问题和第二次悬赏(100 分)
A 部分)仅使用 CSS 为进度(中心部分和左侧彩色条)设置动画的优雅方式,带有缓入缓出动作,页面加载后延迟 1 秒。

B 部分)动画(和数字)应该从 0% 开始,中间部分中显示的数字然后在动画期间增长到 XX%(无论在 html 中设置为 %)并以正确的进度数字结束和右侧水平进度位置。

iCMS 回答:仅使用 CSS 的复杂比例三元进度条设计 浏览器支持 value

你可以像下面这样做。我使用不同的颜色来更好地查看结果

body {
  margin: 100px;
  background: #CCC
}

.fullbar {
  background-color: blue;
}

.progress {
  background: lightgreen;
  margin: 10px 0 0 0;
  height: 5px;
  position:relative; /* relative here */
  width:var(--p);
}

.number {
  position:absolute; /* absolute here */
  background: rgba(255,0.5);
  left:100%; /* push to the right side */
  transform:translateX(calc(-1*var(--p))); /* offset to the left based on --p */
  top:-10px;
  bottom:-10px;
  color: #FFF;
  padding: 0 2px 1px 3px;
}
<div class="fullbar">
  <div class="progress" style="--p:0%">
    <div class="number">0%</div>
  </div>
</div>

<div class="fullbar">
  <div class="progress" style="--p:20%">
    <div class="number">20%</div>
  </div>
</div>

<div class="fullbar">
  <div class="progress" style="--p:50%">
    <div class="number">50%</div>
  </div>
</div>

<div class="fullbar">
  <div class="progress" style="--p:80%">
    <div class="number">80%</div>
  </div>
</div>

<div class="fullbar">
  <div class="progress" style="--p:100%">
    <div class="number">100%</div>
  </div>
</div>

仅使用一个 div 的另一个想法:

body {
  margin: 100px;
  background: #CCC
}

.progress {
  margin: 20px 0;
  height: 10px;
  position: relative;
  background: linear-gradient(lightgreen 0 0) 0/var(--p) 100% no-repeat blue;
}

.progress::before {
  content: attr(style);
  font-family: monospace;
  font-size:20px;
  white-space:nowrap;
  text-indent: -4ch;
  overflow: hidden;
  position: absolute;
  background: rgba(255,0.8);
  border:5px solid transparent;
  top:50%;
  left: var(--p);
  transform: translate(calc(-1*var(--p)),-50%);
  color: #FFF;
}
<div class="progress" style="--p:0%"></div>

<div class="progress" style="--p:20%"></div>

<div class="progress" style="--p:50%"></div>


<div class="progress" style="--p:80%"></div>

<div class="progress" style="--p:100%"></div>

更新

带动画:

body {
  margin: 100px;
  background: #CCC
}

.progress {
  margin: 20px 0;
  height: 10px;
  position: relative;
  background: linear-gradient(lightgreen 0 0) 0/var(--p) 100% no-repeat blue;
  animation:p1 1s 1s both;
}

.progress::before {
  content: attr(style);
  font-family: monospace;
  font-size:20px;
  white-space:nowrap;
  text-indent: -4ch;
  overflow: hidden;
  position: absolute;
  background: rgba(255,-50%);
  color: #FFF;
  animation:p2 1s 1s both;
}
@keyframes p1 {from {background-size:0 100%}}
@keyframes p2 {from {left:0;transform: translate(0%,-50%)}}
<div class="progress" style="--p:0%"></div>

<div class="progress" style="--p:20%"></div>

<div class="progress" style="--p:50%"></div>

<div class="progress" style="--p:80%"></div>

<div class="progress" style="--p:100%"></div>

对于数字动画,我会使用 @property,但目前仅在 chrome an edge 上可用:

body {
  margin: 100px;
  background: #CCC
}

@property --p {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}
@property --s {
  syntax: '<integer>';
  inherits: true;
  initial-value: 0;
}

.progress {
  margin: 20px 0;
  height: 10px;
  position: relative;
  background: linear-gradient(lightgreen 0 0) 0/calc(var(--p,0)*1%) 100% no-repeat blue;
  animation:p1 1s 1s both;
  --s:var(--p);
  counter-set:num var(--s);
}

.progress::before {
  content: counter(num) "%";
  font-family: monospace;
  font-size:20px;
  white-space:nowrap;
  overflow: hidden;
  position: absolute;
  background: rgba(255,0.8);
  border:5px solid transparent;
  top:50%;
  left: calc(var(--p)*1%);
  transform: translate(calc(-1%*var(--p)),-50%);
  color: #FFF;
}
@keyframes p1 {from {--p:0;--s:0}}
<div class="progress" style="--p:0"></div>

<div class="progress" style="--p:20"></div>

<div class="progress" style="--p:50"></div>


<div class="progress" style="--p:80"></div>

<div class="progress" style="--p:100"></div>

在有更多支持之前,您可以像下面那样伪造它:

body {
  margin: 100px;
  background: #CCC
}

.progress {
  margin: 20px 0;
  height: 10px;
  position: relative;
  background: linear-gradient(lightgreen 0 0) 0/var(--p) 100% no-repeat blue;
  animation:p1 1s 1s both;
}

.progress::before {
  content: attr(style);
  font-family: monospace;
  font-size:20px;
  white-space:nowrap;
  text-indent: -4ch;
  overflow: hidden;
  position: absolute;
  background: rgba(255,-50%);
  color: #FFF;
  animation:p2 1s 1s both,p3 0.8s 1s both;
}
@keyframes p1 {from {background-size:0% 100%}}
@keyframes p2 {from {left:0%;transform: translate(0%,-50%)}}
@keyframes p3 { /* put some randome number to fake the animation*/
  0%  {content:"--p:0%"}
  15% {content:"--p:5%"}
  30% {content:"--p:9%"}
  45% {content:"--p:10%"}
  60% {content:"--p:11%"}
  75% {content:"--p:40%"}
  90% {content:"--p:20%"}
}
<div class="progress" style="--p:0%"></div>

<div class="progress" style="--p:20%"></div>

<div class="progress" style="--p:50%"></div>


<div class="progress" style="--p:80%"></div>

<div class="progress" style="--p:100%"></div>

或者像下面这样的疯狂想法:

body {
  margin: 100px;
  background: #CCC
}

.progress {
  margin: 20px 0;
  height: 10px;
  position: relative;
  background: linear-gradient(lightgreen 0 0) 0/calc(var(--p)*1%) 100% no-repeat blue;
  animation:p1 1s 1s both;
}

.progress::before {
  content: "0% \A 1% \A 2% \A 3% \A 4% \A 5% \A 6% \A 7% \A 8% \A 9% \A 10% \A 11% \A 12% \A 13% \A 14% \A 15% \A 16% \A 17% \A 18% \A 19% \A 20% \A 21% \A 22% \A 23% \A 24% \A 25% \A 26% \A 27% \A 28% \A 29% \A 30% \A 31% \A 32% \A 33% \A 34% \A 35% \A 36% \A 37% \A 38% \A 39% \A 40% \A 41% \A 42% \A 43% \A 44% \A 45% \A 46% \A 47% \A 48% \A 49% \A 50% \A 51% \A 52% \A 53% \A 54% \A 55% \A 56% \A 57% \A 58% \A 59% \A 60% \A 61% \A 62% \A 63% \A 64% \A 65% \A 66% \A 67% \A 68% \A 69% \A 70% \A 71% \A 72% \A 73% \A 74% \A 75% \A 76% \A 77% \A 78% \A 79% \A 80% \A 81% \A 82% \A 83% \A 84% \A 85% \A 86% \A 87% \A 88% \A 89% \A 90% \A 91% \A 92% \A 93% \A 94% \A 95% \A 96% \A 97% \A 98% \A 99% \A 100%";
  font-family: monospace;
  font-size:20px;
  width:4ch;
  line-height:1em;
  height:1em;
  text-align:center;
  overflow: hidden;
  position: absolute;
  background: rgba(255,-50%);
  color: #0000;
  text-shadow:0 calc(var(--p)*-1em) 0 #fff;
  animation:p2 1s 1s both,p3 1s 1s steps(var(--p)) both;
}
@keyframes p1 {from {background-size:0% 100%}}
@keyframes p2 {from {left:0%;transform: translate(0%,-50%)}}
@keyframes p3 {from {text-shadow:0 0 0 #fff}}
<div class="progress" style="--p:0"></div>

<div class="progress" style="--p:20"></div>

<div class="progress" style="--p:50"></div>

<div class="progress" style="--p:80"></div>

<div class="progress" style="--p:100"></div>

,

@Temaninailed it 及其解决方案。他完成了所有的跑腿工作;我是来补充他的最后一个解决方案的。

我改变的是这个:

  • 进度条的左侧和右侧现在是两个独立的(伪)元素,并使用 flex-grow 增长到正确的比例 - 使用更少的 calc
  • 拇指不再需要手动定位。它通过使用 flex-box 和伪元素来定位。
  • 拇指又是一个自己的元素。这样,我可以使数字再次成为真实文本,而不是 text-shadow。如果你想把这个东西变成一个滑块,你也可以使用 JS 来捕捉事件。
  • 移除了透明边框。我认为这有点太hacky了。只是将行高从 1em 增加到 2em 并添加了 (2em - 1em) * -0.5 = -0.5em 的偏移量。

body {
  margin: 0;
  padding: 20px;
  background: #EEE;
  font-family: sans-serif;
}

.progress {
  display: flex;
  align-items: center;
  margin: 20px;
  animation-delay: 1s;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}

.progress::before,.progress::after {
  content: '';
  height: 10px;
  animation: inherit;
}

.progress::before {
  background-color: #1306F8;
  flex-grow: 0;
  animation-name: p_before;
}

.progress::after {
  background-color: #E1E1E1;
  flex-grow: 100;
  animation-name: p_after;
}

.progress .thumb {
  height: 1em;
  padding: .3em .4em;
  font-size: 20px;
  line-height: 2em;
  text-align: center;
  color: #FFF;
  background-color: #1306F8;
  overflow: hidden;
  z-index: 1;
  animation: inherit;
}

.progress .thumb::before {
  content: "0% \A 1% \A 2% \A 3% \A 4% \A 5% \A 6% \A 7% \A 8% \A 9% \A 10% \A 11% \A 12% \A 13% \A 14% \A 15% \A 16% \A 17% \A 18% \A 19% \A 20% \A 21% \A 22% \A 23% \A 24% \A 25% \A 26% \A 27% \A 28% \A 29% \A 30% \A 31% \A 32% \A 33% \A 34% \A 35% \A 36% \A 37% \A 38% \A 39% \A 40% \A 41% \A 42% \A 43% \A 44% \A 45% \A 46% \A 47% \A 48% \A 49% \A 50% \A 51% \A 52% \A 53% \A 54% \A 55% \A 56% \A 57% \A 58% \A 59% \A 60% \A 61% \A 62% \A 63% \A 64% \A 65% \A 66% \A 67% \A 68% \A 69% \A 70% \A 71% \A 72% \A 73% \A 74% \A 75% \A 76% \A 77% \A 78% \A 79% \A 80% \A 81% \A 82% \A 83% \A 84% \A 85% \A 86% \A 87% \A 88% \A 89% \A 90% \A 91% \A 92% \A 93% \A 94% \A 95% \A 96% \A 97% \A 98% \A 99% \A 100%";
  position: relative;
  display: block;
  text-align: center;
  white-space: pre-line;
  margin-top: -0.5em;
  top: 0;
  animation: inherit;
  animation-timing-function: steps(var(--p));
  animation-name: p_thumb;
}

@keyframes p_before { to { flex-grow:             var(--p)  } }
@keyframes p_after  { to { flex-grow: calc( 100 - var(--p)) } }
@keyframes p_thumb  { to { top:       calc(-2em * var(--p)) } }
<div class="progress" style="--p:0"><div class="thumb"></div></div>
<div class="progress" style="--p:20"><div class="thumb"></div></div>
<div class="progress" style="--p:40"><div class="thumb"></div></div>
<div class="progress" style="--p:60"><div class="thumb"></div></div>
<div class="progress" style="--p:80"><div class="thumb"></div></div>
<div class="progress" style="--p:100"><div class="thumb"></div></div>

就像我说的那样,Temani 完成了跑腿工作,可能应该按计划获得赏金(奖励现有答案)。

,

到目前为止的答案非常好,尤其是 Temani Afif 的文本缩进技巧。

我最初考虑做类似的事情,但想朝不同的方向发展。最后,我确定了一个解决方案,它利用新的 CSS Houdini @property 定义和一些 counter-reset 技巧将数字 CSS 自定义属性转换为字符串,然后我们可以在 {{1} } 我们添加的伪选择器的属性。

TL;DR

这是我的解决方案的完整代码片段,也在下面的详细说明中。

content
@property --progress-value {
  syntax: "<integer>";
  inherits: true;
  initial-value: 0;
}
:root {
  --progress-bar-color: #cfd8dc;
  --progress-value-color: #2196f3;
  --progress-empty-color-h: 4.1;
  --progress-empty-color-s: 89.6;
  --progress-empty-color-l: 58.4;
  --progress-filled-color-h: 122.4;
  --progress-filled-color-s: 39.4;
  --progress-filled-color-l: 49.2;
}

html,body {
  height: 100%;
}

body {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  flex-direction: column;
  margin: 0;
  font-family: "Roboto Mono",monospace;
}

progress[value] {
  display: block;
  position: relative;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  height: 6px;
  border: 0;
  --border-radius: 10px;
  border-radius: var(--border-radius);
  counter-reset: progress var(--progress-value);
  --progress-value-string: counter(progress) "%";
  --progress-max-decimal: calc(var(--value,0) / var(--max,0));
  --progress-value-decimal: calc(var(--progress-value,0));
  --progress-value-percent: calc(var(--progress-value-decimal) * 100%);
  --progress-value-color: hsl(
    calc((var(--progress-empty-color-h) + (var(--progress-filled-color-h) - var(--progress-empty-color-h)) * var(--progress-value-decimal)) * 1deg)
    calc((var(--progress-empty-color-s) + (var(--progress-filled-color-s) - var(--progress-empty-color-s)) * var(--progress-value-decimal)) * 1%)
    calc((var(--progress-empty-color-l) + (var(--progress-filled-color-l) - var(--progress-empty-color-l)) * var(--progress-value-decimal)) * 1%)
  );
  -webkit-animation: calc(1s * var(--progress-max-decimal)) ease-out 0s 1 normal both progress;
          animation: calc(1s * var(--progress-max-decimal)) ease-out 0s 1 normal both progress;
}
@supports selector(::-moz-progress-bar) {
  progress[value] {
    --progress-value-decimal: calc(var(--value,0));
  }
}

progress[value]::-webkit-progress-bar {
  background-color: var(--progress-bar-color);
  border-radius: var(--border-radius);
  overflow: hidden;
}

progress[value]::-webkit-progress-value {
  width: var(--progress-value-percent) !important;
  background-color: var(--progress-value-color);
  border-radius: var(--border-radius);
}

progress[value]::-moz-progress-bar {
  width: var(--progress-value-percent) !important;
  background-color: var(--progress-value-color);
  border-radius: var(--border-radius);
}

progress[value]::after {
  display: flex;
  align-items: center;
  justify-content: center;
  --size: 32px;
  width: var(--size);
  height: var(--size);
  position: absolute;
  left: var(--progress-value-percent);
  top: 50%;
  transform: translate(-50%,-50%);
  background-color: var(--progress-value-color);
  border-radius: 50%;
  content: attr(value);
  content: var(--progress-value-string,var(--value));
  font-size: 12px;
  font-weight: 700;
  color: #fff;
}

@-webkit-keyframes progress {
  from {
    --progress-value: 0;
  } to {
    --progress-value: var(--value);
  }
}

@keyframes progress {
  from {
    --progress-value: 0;
  } to {
    --progress-value: var(--value);
  }
}

CodePen 链接: cdpn.io/e/RwpyZGo

最终产品(屏幕截图,点击上面附加代码片段底部的“运行片段”以查看动画效果)。

CSS styled animated progress bars

详细说明

HTML 已经有一个内置的 <progress> 元素,其中包含几个伪元素,所以我真的想坚持使用它并围绕它设置样式。事实证明,当与 CSS Houdini 的新 @property 定义结合使用时,这在很大程度上取得了成功,这使我们能够创建更多动态动画等。

事实上,Temani Afif 对这个问题发布了另一个很好的答案,在这里写了一篇很棒的文章(We can finally animate CSS gradient 由 Temani Afif)。

使用新的 @property 定义不仅允许我们为进度条的实际值设置动画,我们可以使用它来更改进度条内进度值的宽度以及 {{1 }} 标签,但它也允许我们随着进度变化生成动态颜色变化。

在下面的示例中,我选择从红色过渡到绿色来表示进度。如果您更喜欢使用单一颜色而不是这种不断变化的颜色,只需将所有 <progress value="0" max="100" style="--value: 0; --max: 100;"></progress> <progress value="25" max="100" style="--value: 25; --max: 100;"></progress> <progress value="50" max="100" style="--value: 50; --max: 100;"></progress> <progress value="75" max="100" style="--value: 75; --max: 100;"></progress> <progress value="100" max="100" style="--value: 100; --max: 100;"></progress> HSL 值替换为单一颜色值。

同样,我在 % 行中使用了 --progress-value-color 来调整每个进度条动画的 calc() 以相同的速率移动,这样而不是所有进度条的开始并同时完成他们的动画,每个进度条同时传递相同的值。这意味着,如果两个进度条达到 50%,其中一个的值为 50%,则该进度条将停止动画,而另一个将继续动画到其新值。

如果您希望所有进度条开始和结束同步,只需将该 animation 替换为单个 <time> 值(例如 animation-durationcalc() 等.).

750ms
3s

CodePen 链接: cdpn.io/e/RwpyZGo


对于每个进度条,我们都需要将 @property --progress-value { syntax: "<integer>"; inherits: true; initial-value: 0; } :root { --progress-bar-color: #cfd8dc; --progress-value-color: #2196f3; --progress-empty-color-h: 4.1; --progress-empty-color-s: 89.6; --progress-empty-color-l: 58.4; --progress-filled-color-h: 122.4; --progress-filled-color-s: 39.4; --progress-filled-color-l: 49.2; } html,var(--value)); font-size: 12px; font-weight: 700; color: #fff; } @-webkit-keyframes progress { from { --progress-value: 0; } to { --progress-value: var(--value); } } @keyframes progress { from { --progress-value: 0; } to { --progress-value: var(--value); } }<progress value="0" max="100" style="--value: 0; --max: 100;"></progress> <progress value="25" max="100" style="--value: 25; --max: 100;"></progress> <progress value="50" max="100" style="--value: 50; --max: 100;"></progress> <progress value="75" max="100" style="--value: 75; --max: 100;"></progress> <progress value="100" max="100" style="--value: 100; --max: 100;"></progress> 声明为属性和 CSS 自定义属性(变量),这当然不是理想的。但是,CSSWG 目前正在对 attr() 进行一些不同的改进,这将使我们能够很快以任何指​​定格式访问这些属性值,而无需像我在上面的示例中那样额外使用 CSS 自定义属性。>

浏览器支持 value

CSS attr browser support

正如您在官方 MDN docs on attr() 的浏览器支持部分中看到的那样^,目前几乎没有浏览器支持 max 的这些附加功能,例如回退和类型或单位.我们还需要能够在任何 CSS 属性中使用 attr(),尤其是 CSS 自定义属性,而不仅仅是 attr() 属性,以便完全不用 CSS 自定义属性解决方法。

这些改进目前处于“编辑草案”状态,不支持生产浏览器,但最早可能会在明年发生变化。所以现在,除了属性之外,我们还需要使用 CSS 自定义属性。此外,Firefox 尚不支持此新属性定义,但我的解决方案包括 attr() 查询回退,它仍然可以确保进度条具有正确的宽度并根据其值使用正确的颜色。

一旦所有这些 CSS 和 Houdini 更新都可以在所有主要浏览器上使用,希望明年,所有这些都可以通过这样的原生 HTML 属性实现:

content

到那时,我们将能够在 CSS 中以这种方式设置它们,而不是使用 CSS 自定义属性值 @supports<progress value="0" max="100"></progress> <progress value="25" max="100"></progress> <progress value="50" max="100"></progress> <progress value="75" max="100"></progress> <progress value="100" max="100"></progress>

--value

其余的逻辑将保持不变。有关 --max 的更多详细信息,请参考此处的 MDN 文档:attr()

,

除了并与我的其他更自定义的解决方案分开之外,我还想发布一个专门回答您最初提出的问题的答案,而不是提供不同的或替代的解决方案。

最内层元素不是完全居中的原因是它的 div 本质上占据了其父级宽度的 100%,由于它具有内联 width 样式,因此占据了其父级宽度的 50%应用于它。文本右对齐,这意味着文本的右侧将正好位于中间 50% 标记的正上方,但它不会完全位于 .fullbar 元素的中心。

在不太自定义的情况下,我个人更愿意将 .number 元素设置为绝对定位 (position: absolute),以便其祖先元素的大小完全不受其自身大小的影响。这样就独立了。

以下是我们如何实现这一目标:

html,body { height: 100%; }

body {
    display: flex;
    align-items: center;
    justify-content: center;
  margin: 0;
  padding: 0 20px;
  background-color: #ccc;
}

.fullbar {
  background-color: blue;
  width: 100%;
  height: 10px;
}

.progress {
  position: relative;
  background: green;
  height: 100%;
}

.number {
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translate(50%,-50%);
  background: inherit;
  color: #fff;
  padding: 4px;
  padding: 0 2px 1px 3px;
}
<div class="fullbar">
  <div class="progress" style="width: 50%">
    <div class="number">50%</div>
  </div>
</div>

最后,如果您确实希望使用 CSS 自定义属性将原始解决方案作为一行工作,我们可以这样做:

html,body { height: 100%; }

body {
    display: flex;
    align-items: center;
    justify-content: center;
  margin: 0;
  padding: 0 20px;
  background-color: #ccc;
}

.progress {
  counter-reset: progress var(--value);
  --value-percent: calc(var(--value) * 1%);
  position: relative;
  width: 100%;
  height: 10px;
  background-color: blue;
}

.progress::before {
  content: '';
  display: block;
  position: relative;
  width: var(--value-percent);
  height: 100%;
  background: green;
}

.progress::after {
  content: counter(progress) '%';
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  left: var(--value-percent);
  top: 50%;
  transform: translate(-50%,-50%);
  background: green;
  color: #fff;
  padding: 2px 4px;
}
<div class="progress" style="--value: 50"></div>

本文链接:https://www.f2er.com/414484.html

大家都在问