最近遇到的奇葩进度条
前言
本文将介绍几个我最近遇到的奇葩进度条,需求看似简单,但是我们可以用平常巧妙的属性来解决,再也不用复杂的html结构和颜色渐变算法。
“奇葩”的环形渐变进度条
需求描述:需要环形渐变的进度条让人快速理解进度实现程度,10-20%是青绿色,20%到30%是黄色.....
乍一看是不是很容易,但是我思来想去用了echarts的svg渲染,但是只要到了90%,一定会渐变到青绿色,从红色渐变到青绿色,做实让我心一凉。
思路一:径向渐变分割
网上思路很多,稍微复杂的比如分割区域做大量的颜色的径向渐变。原理是将rgba转为16进制计算颜色插值。这样我们通过计算step步长就可以根据细分做渐变了。但是好像无法很好满足我们的指定区域10%-20%是某种颜色,虽然可以但是也太麻烦了。
function gradientColor(startRGB, endRGB, step) {
let startR = startRGB[0]
let startG = startRGB[1]
let startB = startRGB[2]
let endR = endRGB[0]
let endG = endRGB[1]
let endB = endRGB[2]
let sR = (endR - startR) / step // 总差值
let sG = (endG - startG) / step
let sB = (endB - startB) / step
var colorArr = []
for (var i = 0; i < step; i++) {
let color = 'rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')'
colorArr.push(color)
}
return colorArr
}
思路二:CSS结合svg
我们可以用css的background: conic-gradient
background: conic-gradient(#179067, #62e317, #d7f10f, #ffc403, #fcc202, #ff7327, #ff7327, #FF5800, #ff5900, #f64302, #ff0000, #ff0000);
看着好像不错,那么接下来只要我们做个遮罩,然后用svg的strokeDashoffset来形成我们的环状进度条就可以了。至于百分之几到百分之几我们可以将conic-gradient内部属性做个百分比的拆分就可以了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.circle {
width: 300px;
height: 300px;
background: conic-gradient(#179067, #62e317, #d7f10f, #ffc403, #fcc202, #ff7327, #ff7327, #FF5800, #ff5900, #f64302, #ff0000, #ff0000);
border-radius: 50%;
position: relative;
}
#progress-circle circle {
stroke-dasharray: 880;
stroke: #f2f2f2;
}
#progress-circle {
transform: rotate(-90deg);
}
.circle-mask {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
width: 260px;
height: 260px;
background: #fff;
border-radius: 50%;
}
</style>
<body>
<div class="circle">
<svg id="progress-circle" width="300" height="300">
<circle r="140" cx="150" cy="150" stroke-width="21" fill="transparent" />
</svg>
<div class="circle-mask"></div>
</div>
</body>
<script>
const circle = document.querySelector('#progress-circle circle');
const radius = circle.r.baseVal.value;
const circumference = radius * 2 * Math.PI;
function setProgress(percent) {
const progress = circumference - (percent / 100) * circumference;
circle.style.strokeDashoffset = -progress;
}
let prog = 40
let val = 100 - prog
setProgress(val); //设置初始进度
</script>
</html>
这里简单讲下逻辑,我们通过计算环的周长,总长其实就是stroke-dasharray,通过strokeDashoffset来偏移我们的虚线线段,那么开始的就是我们的实线线段。其实就是一个蚂蚁线。让这个线长度等于我们的环长度,通过api让实线在开始的位置。
最终效果
"奇葩"的横向进度条
在我们平常需求用用组件库实现进度条很容易,但是我们看看这个需求的进度条的场景,文字要能被裁剪成黑白两色。
思路一: overflow:hidden
具体就不演示了,内部通过两个副本的文案,一套白色一套黑色,通过定位层级的不同,overflow:hidden来隐藏,缺点是相对繁琐的dom结构。
思路二: background-clip 裁剪
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
:root {
--d: 20%
}
.inverted {
padding: 0 8px;
display: flex;
justify-content: space-between;
background: linear-gradient(-90deg, #000 var(--d), #fff 0) no-repeat, linear-gradient(-90deg, #0000 var(--d), rgb(192, 23, 23) 0) no-repeat;
-webkit-background-clip: text, padding-box;
background-clip: text, padding-box;
color: #0000;
font-weight: bold;
cursor: pointer;
}
.box {
background: #ebebeb;
width: 300px;
border-radius: 24px;
overflow: hidden;
}
</style>
<body>
<div class="box">
<div class="inverted">
<div class="inverted-item">888w/12</div>
<div class="inverted-item">100%/10s</div>
</div>
</div>
</body>
<script>
function modifyProg(prog) {
let val = 100 - prog
document.documentElement.style.setProperty('--d', val + '%')
}
modifyProg(6)
</script>
</html>
这里我们主要用了background-clip的text和padding-box两个裁剪,一个裁剪文本,一个裁剪背景延伸至内边距padding外沿。不会绘制到边框处。在js中我们通过setProperty修改css变量即可。