一、源起

在沪江上学习的时候,总是会在班级主页看到这样的环形进度条:

翻看源码,嗯,是用 Canvas 做的。什么!Canvas!臣妾还不会玩啊%#%¥#¥%

“要不就试试能不能用 CSS 写一个出来吧 (/ω\*)”

二、ご注文は「プログレスリング」ですか

那么,请问您今天要来点「环形进度条」么?

经过两个晚上的折腾,终于搞出点东西来了↓ 如果您手头正在使用的是 IE10+ 之类支持 CSS3 Animation 的浏览器,请戳 Demo

三、原理分析

1 . 要让进度条一点一点转出来,肯定是不能用完整的一个圆环的。于是就出现了下面这张图示的空间结构:

一个完整的圆转不出效果来,那就劈开来嘛,半个环总是可以转的!这里用到了 clip 属性 来切割圆环;在左右两个表示进度的半圆环之外,我们还添加了一个遮罩,做障眼法之用。

对应的代码:

<div class="progress-ring">  
    <div class="progress-track"></div>
    <div class="progress-left"></div>
    <div class="progress-right"></div>
    <div class="progress-cover"></div>
</div>  
$size: 130px; // 圆环宽高
$borderWidth: ($size / 8); // 轨道宽度
$fontColor: #949494; // 文字颜色

@mixin positioning($pos: absolute) {
    position: $pos;
    top: 0;
    left: 0;
    height: $size;
    width: $size;
}

.progress-ring {
    @include positioning(relative);
    div {
        @include positioning;
        border: $borderWidth solid #31ae48;
        border-radius: 50%;
        box-sizing: border-box;
    }
    .progress-left, .progress-right, .progress-cover {
        clip: rect(0 ($size / 2) $size 0); /* [0 | <width/2> | <width> | 0] */
    }
    .progress-right {
        transform: rotate(180deg); /* 旋转到右边 */
    }
    .progress-left, .progress-right {
        border-color: #ffaa05;
    }
}

2 . 旋转动画开始时,让右半边的圆环隐藏了,遮罩覆盖住左半边的圆环。于是你看到的只有旋转出来的那一点点不安分的环:

对应的代码:

$precent: 5; // 进度百分比
$duration: 2s; // 动画时长

.progress-right {
    opacity: 0;
}
.progress-left {
    transform: rotate(3.6deg * $precent);
    transition: transform $duration linear;
}

3 . 旋转到一半时,左右两个半环重叠在一起,于是图形变成了这样:

4 . 这时问题来了:旋转过半的时候,要怎样处理圆环才能让进度显示出来?

这时应该让遮罩隐藏,右边的半圆环显示出来,左边的半圆环继续旋转

这里比较不好控制的是消失的时间。JavaScript?No no no,说好要用 CSS 了。于是这时我们要借助 CSS3 animationtiming-function 属性了:

@keyframes toggle {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}
.progress-right {
    opacity: 1;
    animation: toggle($duration * 50 / $precent) step-end;
}
.progress-cover {
    opacity: 0;
    animation: toggle($duration * 50 / $precent) step-start;
}

5 . 动画完成,左右两个半环对接,填满整个轨道

四、一点改进

至此已经可以实现环形进度条的整个动画了,但是一想到每次要用进度条都要写这么多代码就菊花一紧。于是又花了些时间编写了一个 jQuery 插件,点我下载

用法

  1. 引入jquery-2.1.1.min.js、progress-ring.js、progress-ring.css

  2. 创建标签 <div class="progress-ring"></div>

  3. 使用如下语句激活插件:$(".progress-ring").loadingRing();

可选参数

插件采用 data 属性来调用参数,以下参数均为可选参数。

选项 描述 默认值
data-percent 进度的百分比,例如data-percent="67" 75
data-color 轨道颜色和进度颜色,例如data-color="blue,yellow",则轨道颜色为blue,进度颜色为yellow #f0f0f0,#6ec84e
data-duration 动画持续时间(秒),例如data-duration="4",则动画播放4秒 1.5

(全文完)

参考资料:

  1. CSS3实现鸡蛋饼饼状图loading等待转转转 - 张鑫旭-鑫空间-鑫生活
  2. animation-timing-function
  3. -webkit-animation-timing-function | CtripUED Webkit CSS Library