需求:我们在开发中会遇到使用各式各样的进度条,因为当前插件里面进度条各式各样的,为了方便我们定制化的开发和方便修改样式,我们这里使用HTML和CSS样式来进行开发进度条功能。
通过本文学习我们会明白如何使用 HTML/CSS 创建各种基础进度条及花式进度条及其动画的方式。
- 通过 HTML 标签 meter 创建进度条
- 通过 HTML 标签progress创建进度条
- HTML 实现进度条的局限性
- 使用 CSS 百分比、渐变创建普通进度条及其动画
- 使用 CSS 创建圆环形进度条
- 使用 CSS 创建球形进度条
1,横向进度条效果如下
我们最为常见遇到进度条是横向进度条。这个是最多的,主要利用HTML5 原生提供了两个标签 和 来实现进度条。
meter 具体实例如下:
<p> <span>完成度:</span> <meter min="0" max="500" value="350">350 degrees</meter> </p>
其中,min、max、value 分别表示最大值,最小值与当前值。
我们再来看看 标签的用法:
<p> <label for="file">完成度:</label> <progress max="100" value="70"> 70% </progress> </p>
其中,max 属性描述这个 progress 元素所表示的任务一共需要完成多少工作量,value 属性用来指定该进度条已完成的工作量。
二者比较差异如下:
那么问题来了,从上述 Demo 看,两个标签的效果一模一样,那么它们的区别是什么?为什么会有两个看似一样的标签呢?
这两个元素最大的差异在于语义上的差别。
meter 表示已知范围内的标量测量值或分数值
progress 表示任务的完成进度
譬如,一个需求当前的完成度,应该使用 ,而如果要展示汽车仪表盘当前的速度值,应该使用 meter。
meter & progress 的局限性
当然,在实际的业务需求中,或者生产环境,你几乎是不会看到meter 和progress 标签。
我们无法有效的修改meter和 progress标签的样式,譬如背景色,进度前景色等。并且,最为致命的是,浏览器默认样式的表现在不同浏览器之间并不一致。这给追求稳定,UI 表现一致的业务来说,是灾难性的缺点!
我们无法给他添加一些动画效果、交互效果,因为一些实际的应用场景中,肯定不是简单的展示一个进度条仅此而已
利用 CSS 实现进度条
因此,在现阶段,更多的还是使用一些 CSS 的方式去实现进度条。
(1)使用百分比实现进度条
最为常见的一种方式是使用背景色配合百分比的方式制作带有渐变的进度条。
最简单的一个 DEMO示例如下:
<div class="g-container"> <div class="g-progress"></div> </div> <div class="g-progress"></div>
同样的,我们可以利用 HTML style 属性填写完整的 background 值传递实际百分比,当然,这里更推荐使用 CSS 自定义属性传值
为了实现动画效果,我们可以借助 CSS @property,改造下我们的代码:
<div class="g-progress" style="--progress: 70%"></div> @property --progress { syntax: '<percentage>'; inherits: false; initial-value: 0%; } .g-progress { margin: auto; width: 240px; height: 25px; border-radius: 25px; background: linear-gradient(90deg, #0f0, #0ff var(--progress), transparent 0); border: 1px solid #eee; transition: .3s --progress; }
2,圆形进度条效果如下:
核心就是使用角向渐变 background: conic-gradient():
示例效果如下:
代码如下:
<div class="progress-circle" v-for="(item,index) in progressList" :key="index" :style="{ background: `radial-gradient(#fff 55%, transparent 56%), conic-gradient(#3A7CFF ${item.rate}%, #f5f5f5 ${ item.rate && item.rate > 0 ? item.rate + 0.4 : 0 }%),radial-gradient(#fff 60%, #F1F3FC 0%);` } "> <span class="progress-value" >{{item.name}}</span> <div class="totalvalbox" > {{ item.rate }}% </div> </div> <style lang="scss" scoped> .progress-circle { position: relative; width: 149rpx; height: 149rpx; font-family: PingFang SC; border-radius: 50%; display: flex; align-items: center; justify-content: center; } .progress-value { position: absolute; text-align: center; line-height: 50rpx; width: 100%; font-weight: 400; font-size: 26rpx; } .totalvalbox { min-width: 217rpx; text-align: center; position: absolute; bottom: -50rpx; font-weight: 400; font-size: 30rpx; } </style>
优化问题如下:
这里容易出现的问题如下:
角向渐变实现圆弧进度条的局限性
当然,这个方法有两个弊端。
当然进度百分比不是类似于 0°、90°、180°、270°、360° 这类数字时,使用角向渐变时,不同颜色间的衔接处会有明显的锯齿。
看个例子 conic-gradient(#FFCDB2 0, #FFCDB2 27%, #B5838D 27%, #B5838D):
遇到此类问题的解决方案是,在衔接处,适当留出一些渐变空间,我们简单的改造一下上述角向渐变代码:
{ - background: conic-gradient(#FFCDB2 0, #FFCDB2 27%, #B5838D 27%, #B5838D)` + background: conic-gradient(#FFCDB2 0, #FFCDB2 27%, #B5838D 27.2%, #B5838D)` }
仔细看上面的代码,将从 27% 到 27% 的一个变化,改为了 从 27% 到 27.2%,这多出来的 0.2% 就是为了消除锯齿的,实际改变后的效果:
我们在有些情况会遇到进度条收尾用圆角的进度条,这种情况当然进度条颜色是纯色也是可以解决的,我们通过在在首尾处叠加两个小圆圈即可实现这种效果。
如果进度条是渐变色的话,这种进度条则需要借助 SVG/Canvas 实现了
实例如下:
html
<div class="g-progress"></div> <div class="g-container"> <div class="g-progress"></div> <div class="g-circle"></div> </div>
css
body, html { width: 100%; height: 100%; display: flex; } .g-container { position: relative; margin: auto; width: 200px; height: 200px; } .g-progress { position: relative; margin: auto; width: 200px; height: 200px; border-radius: 50%; background: conic-gradient(#FFCDB2 0, #FFCDB2 25%, #B5838D 25%, #B5838D); mask: radial-gradient(transparent, transparent 80px, #000 80.5px, #000 0); } .g-circle { position: absolute; top: 0; left: 0; &::before, &::after { content: ""; position: absolute; top: 90px; left: 90px; width: 20px; height: 20px; border-radius: 50%; background: #FFCDB2; z-index: 1; } &::before { transform: translate(0, -90px); } &::after { transform: rotate(90deg) translate(0, -90px) ; } }
基于此拓展,还可以实现多色的圆弧型进度条:(这个可能不像进度条,更类似于饼图)
.g-progress { width: 160px; height: 160px; border-radius: 50%; mask: radial-gradient(transparent, transparent 50%, #000 51%, #000 0); background: conic-gradient( #FFCDB2 0, #FFCDB2 25%, #B5838D 25%, #B5838D 50%, #673ab7 50%, #673ab7 90%, #ff5722 90.2%, #ff5722 100% ); }
3,球形进度条效果如下
球形进度条也是比较常见的,类似于下面这种:
核心代码如下:
控制一下球形容器表示进度 0% - 100% 时的波浪的高度即可。我们就能得到从 0% - 100% 的动画效果
<div class="container"> <div class="wave-change"></div> <div class="wave"></div> </div> .container { width: 200px; height: 200px; border: 5px solid rgb(118, 218, 255); border-radius: 50%; overflow: hidden; } .wave-change { position: absolute; width: 200px; height: 200px; left: 0; top: 0; animation: change 12s infinite linear; &::before, &::after{ content: ""; position: absolute; width: 400px; height: 400px; top: 0; left: 50%; background-color: rgba(255, 255, 255, .6); border-radius: 45% 47% 43% 46%; transform: translate(-50%, -70%) rotate(0); animation: rotate 7s linear infinite; z-index: 1; } &::after { border-radius: 47% 42% 46% 44%; background-color: rgba(255, 255, 255, .8); transform: translate(-50%, -70%) rotate(0); animation: rotate 9s linear -4s infinite; z-index: 2; } } .wave { position: relative; width: 200px; height: 200px; background-color: rgb(118, 218, 255); border-radius: 50%; } p { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 36px; color: #000; z-index: 10; } @keyframes rotate { to { transform: translate(-50%, -70%) rotate(360deg); } } @keyframes change { from { top: 80px; } to { top: -120px; } }
4,炫酷的充电进度条如下
当然,CSS 千变万化,进度条的种类肯定也不仅仅局限于上述的几类。譬如我们可以利用滤镜实现的仿华为手机的充电动画,也是一种进度条的呈现方式,也是能够使用纯 CSS 实现的:
核心代码如下
<div class="g-container"> <div class="g-number">98.7%</div> <div class="g-contrast"> <div class="g-circle"></div> <ul class="g-bubbles"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> html, body { width: 100%; height: 100%; display: flex; background: #000; overflow: hidden; } .g-number { position: absolute; width: 300px; top: 27%; text-align: center; font-size: 32px; z-index: 10; color: #fff; } .g-container { position: relative; width: 300px; height: 400px; margin: auto; } .g-contrast { filter: contrast(10) hue-rotate(0); width: 300px; height: 400px; background-color: #000; overflow: hidden; animation: hueRotate 10s infinite linear; } .g-circle { position: relative; width: 300px; height: 300px; box-sizing: border-box; filter: blur(8px); &::after { content: ""; position: absolute; top: 40%; left: 50%; transform: translate(-50%, -50%) rotate(0); width: 200px; height: 200px; background-color: #00ff6f; border-radius: 42% 38% 62% 49% / 45%; animation: rotate 10s infinite linear; } &::before { content: ""; position: absolute; width: 176px; height: 176px; top: 40%; left: 50%; transform: translate(-50%, -50%); border-radius: 50%; background-color: #000; z-index: 10; } } .g-bubbles { position: absolute; left: 50%; bottom: 0; width: 100px; height: 40px; transform: translate(-50%, 0); border-radius: 100px 100px 0 0; background-color: #00ff6f; filter: blur(5px); } li { position: absolute; border-radius: 50%; background: #00ff6f; } @for $i from 0 through 15 { li:nth-child(#{$i}) { $width: 15 + random(15) + px; left: 15 + random(70) + px; top: 50%; transform: translate(-50%, -50%); width: $width; height: $width; animation: moveToTop #{random(6) + 3}s ease-in-out -#{random(5000)/1000}s infinite; } } @keyframes rotate { 50% { border-radius: 45% / 42% 38% 58% 49%; } 100% { transform: translate(-50%, -50%) rotate(720deg); } } @keyframes moveToTop { 90% { opacity: 1; } 100% { opacity: .1; transform: translate(-50%, -180px); } } @keyframes hueRotate { 100% { filter: contrast(15) hue-rotate(360deg); } }
5,拖拽与延伸
最后推荐几款好高质量更为酷炫的进度条
上述效果的完整实现可以戳 – 巧用 CSS 实现酷炫的充电动画