likes
comments
collection
share

最近遇到的奇葩进度条

作者站长头像
站长
· 阅读数 20

前言

本文将介绍几个我最近遇到的奇葩进度条,需求看似简单,但是我们可以用平常巧妙的属性来解决,再也不用复杂的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变量即可。

最终效果

最近遇到的奇葩进度条

附录