CSS 进度条

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

我做了一些进度条。它们看起来像这样

它们不使用任何图像,只使用 CSS3 特效。就像一个优秀的设计师总是会做的那样,它们回退到完全可以接受的体验。以下是它们在 Opera 11 中的样子,Opera 11 支持此处使用的一些 CSS3,但并非全部。

正如您可能想象的那样,在完全不支持 CSS3 的浏览器中,外观将类似于上面所示,只是更加简化。

更新:已经过去一段时间了。本文最初写于 2011 年,并在 2015 年进行了更新,现在又在 2021 年更新。这次我只是修改了演示和代码笔,并删除了许多不再需要的供应商前缀内容。从语义上讲,您可能最好查看<progress><meter>元素。

HTML 基础

进度条本身将是一个带有<div>类名的meter。其中包含一个充当进度条“填充”区域的<span>。这使用内联样式设置。它是知道填充进度条多远的标记,因此在这种情况下,内联样式非常有意义。CSS 替代方法是创建诸如“fill-10-percent”、“fill-one-third”或类似的类,这更繁重且灵活性较差。

基础

<div class="meter">
  <span style="width: 25%"></span>
</div>

CSS 起始

div 包装器是进度条的轨道。我们不会设置宽度,因此它将像块级元素一样扩展到其父元素的宽度。不过您可以设置。高度也是任意的。此处设置为 20px,但可以是任何值。我们将尽可能多地在浏览器中圆角,并设置内阴影以使其具有一定的深度。

.meter { 
  height: 20px;  <em>/* Can be anything */</em>
  position: relative;
  background: #555;
  border-radius: 25px;
  padding: 10px;
  box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3);
}

然后内部的 span 将是进度条的填充部分。我们将使其显示为具有 100% 高度的块,因此它会伸展以适应它具有的任何空间。然后,我们将使用大量 CSS3 来赋予它渐变外观并圆角。

.meter > span {
  display: block;
  height: 100%;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  background-color: rgb(43,194,83);
  background-image: linear-gradient(
    center bottom,
    rgb(43,194,83) 37%,
    rgb(84,240,84) 69%
  );
  box-shadow: 
    inset 0 2px 9px  rgba(255,255,255,0.3),
    inset 0 -2px 6px rgba(0,0,0,0.4);
  position: relative;
  overflow: hidden;
}

这些是基础。

其他颜色

让我们尽可能轻松地更改颜色。只需在 div 包装器中添加一个名为“orange”或“red”的类名,颜色就会被覆盖。

.orange > span {
  background-color: #f1a165;
  background-image: linear-gradient(to bottom, #f1a165, #f36d0a);
}

.red > span {
  background-color: #f0a3a3;
  background-image: linear-gradient(to bottom, #f0a3a3, #f42323);
}

条纹效果

我们可以通过在该 span 的顶部添加另一个元素并在其上放置重复的 CSS3 渐变来获得很酷的条纹效果。从语义上讲,这最好通过伪元素来实现,所以让我们这样做。我们将将其绝对定位在 span 的精确区域(该区域已具有相对定位)上,然后以相同的方式圆角,这样条纹就不会突出得奇怪。

.meter > span:after {
  content: "";
  position: absolute;
  top: 0; left: 0; bottom: 0; right: 0;
  background-image: linear-gradient(
    -45deg, 
    rgba(255, 255, 255, .2) 25%, 
    transparent 25%, 
    transparent 50%, 
    rgba(255, 255, 255, .2) 50%, 
    rgba(255, 255, 255, .2) 75%, 
    transparent 75%, 
    transparent
  );
  z-index: 1;
  background-size: 50px 50px;
  animation: move 2s linear infinite;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  overflow: hidden;
}

我第一次从Lea Verou那里看到并获得了这个想法。

动画条纹

只有 Firefox 4 才能为伪元素设置动画,并且只有 WebKit 才能执行关键帧动画。因此,不幸的是,在为这些条纹设置动画方面,我们处于进退两难的境地。如果我们坚持这样做,让我们添加一个额外的 span,然后 WebKit 为其设置动画。

<div class="meter animate">
  <span style="width: 50%"><span></span></span>
</div>

span 将与伪元素完全相同,因此我们将使用相同的值……

.meter > span:after, .animate > span > span {

……并避免重复

.animate > span::after {
  display: none;
}

我们将背景位置移动到其大小的范围

@keyframes move {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 50px 50px;
  }
}

并调用该动画

.meter > span::after, .animate > span > span {
  animation: move 2s linear infinite;
}

不妨将动画也绑定到伪元素,这样一旦 WebKit 开始支持它,它就会起作用。

动画填充宽度

不幸的是,您无法为自动或自然宽度设置动画,这可能会让我们从强制为零的宽度动画到内联样式。

@keyframes expandWidth {
   0% { width: 0; }
   100% { width: auto; }
}

2012 年 1 月 25 日更新:事实证明,您可以可以为内联样式设置动画。只需在@keyframe中省略“to”或“100%”结束值即可。

我已将其提交给主要浏览器的错误跟踪器,以推动其发展,但目前尚不支持。相反,让我们使用 jQuery 来实现。测量原始宽度,将其强制降低到零,然后动画恢复到原始宽度。

$(".meter > span").each(function() {
  $(this)
    .data("origWidth", $(this).width())
    .width(0)
    .animate({
      width: $(this).data("origWidth") // or + "%" if fluid
    }, 1200);
});

完成了。

其他人的做法

嘿?!HTML5 怎么样?

哥们儿。HTML5 有专门为此设计的特性。<progress><meter>!是的,它确实有,但问题在于。这些元素已经具有非常特定的外观。默认情况下,它们看起来像您所在平台上其他地方使用的进度条。例如在 Mac 上

您可以像这样关闭该默认样式

progress {
  -webkit-appearance: none;
}

这将允许您删除该默认样式中存在的闪亮效果,但您能做的仍然非常有限。您可以像这样更改内部的进度条

progress::-webkit-progress-bar-value {
  -webkit-appearance: none;
  background: orangered;
}

……而且之后您能用它做的事情也相当有限。更糟糕的是,在不同的浏览器之间,甚至在不同的 WebKit 浏览器之间,情况也大不相同。伪元素也无法一致地工作。我不想把事情悬而未决,但这确实是另一个时间的话题。总而言之,对于这些特定的进度条,div/span 方法目前是最佳选择。