Wenzi

使用CSS3实现圆形进度条

蚊子前端博客
发布于 2015/07/27 06:00
一般我们见到的进度条通常都是矩形的,从左往右开始推进,直到100%;但是很少有圆形的进度条,本篇文章稍微讲解下如何使用CSS3实现圆形进度条

一般我们见到的进度条通常都是矩形的,从左往右开始推进,直到 100%;但是很少有圆形的进度条,本篇文章稍微讲解下如何使用 CSS3 实现圆形进度条。

若是只要实现一个圆环的话,我们都能写出来,用borderborder-radius就能画出来:

<style type="text/css">
  .demo {
    width: 200px;
    height: 200px;
    border: 20px solid green;
    box-sizing: border-box;
    border-radius: 50%;
  }
</style>
<div class="demo"></div>

但是这样的圆环不能动啊,而且能产生进度条效果的一个重要的因素就是得从 0 开始变化,而不是一个完整的圆环在旋转,这是没有意义的。首先说下我实现的思路:

  1. 把整个圆环分成左右两部分;
  2. 左右两部分都有半个圆环在旋转,比如先让右边的半圆环,旋转到正好接住了左半部分,然后左边的半圆环开始旋转。

1. 画右半圆环 #

我们先来设计下右半部分吧,html 结构如下:

<div class="right">
  <div class="rightcircle"></div>
</div>

里面的.rightcircle是半个圆环,样式如下:

.right {
  position: relative;
  width: 100px;
  height: 200px;
  overflow: hidden;
}
.rightcircle {
  width: 200px;
  height: 200px;
  border: 20px solid transparent;
  border-radius: 50%;
  position: absolute;
  box-sizing: border-box;
  top: 0;
  right: 0;
  border-top: 20px solid green;
  border-right: 20px solid green;
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg); /* 旋转45度 */
}

当我们把这些样式写完的时候,看到的是这个样子的,因为使用的是 div 的上半边界和右半边界,因此需要旋转一下,才能正好是我们看到的半圆环:

因为外层的 div 有一个overflow:hidden属性,我们先把这个半圆旋转到 div 的另一边隐藏了,然后再慢慢改变这个半圆环的角度,让它显示出来不就行了。稍微计算下就可以知道,-135deg正好能隐藏在外层 div 的左半部分,即:

.rightcircle {
  width: 200px;
  height: 200px;
  border: 20px solid transparent;
  border-radius: 50%;
  box-sizing: border-box;
  position: absolute;
  top: 0;
  right: 0;
  border-top: 20px solid green;
  border-right: 20px solid green;
  transform: rotate(-135deg); /* 旋转45度时正好能显示半个圆,旋转-135度,正好能隐藏半个圆 */
}

20160226 更新

这个-135deg 是怎么得出来的呢,我们来看下面的这张图:

transition

矩形的上边界和右边界正好是对应这上图圆形的上半部分和右半部分,旋转到左侧正好隐藏的话,那就是逆时针旋转-135deg

2. 为半圆添加动画 #

好了,半个圆已经隐藏住了,那么我们应该让它慢慢出来了,给.rightcircle添加一个动画:animation

/* 这里仅考虑webkit内核的情况,您可以写完整了 */
.rightcircle {
  -webkit-animation-name: circle_right; /* 动画名称 */
  -webkit-animation-duration: 5s; /* 完成一个动画需要的时间 */
  -webkit-animation-timing-function: linear; /* 动画播放的方式,linear是匀速变化 */
  -webkit-animation-iteration-count: infinite; /* 动画播放的次数,infinite是无限次数 */
}

@-webkit-keyframes circle_right {
  0% {
    transform: rotate(-135deg);
  }
  100% {
    transform: rotate(45deg);
  }
}

那么左半部分就正好相反喽,这里我就不写了,你可以尝试着写一下。

3. 大功告成 #

好了,让我们把左半部分和右半部分拼接起来:

<style>
  .circle_process {
    position: relative;
    width: 199px;
    height: 200px;
  }
  .circle_process .wrapper {
    width: 100px;
    height: 200px;
    position: absolute;
    top: 0;
    overflow: hidden;
  }
  .circle_process .right {
    right: 0;
  }
  .circle_process .left {
    left: 0;
  }
  .circle_process .circle {
    width: 200px;
    height: 200px;
    border: 20px solid transparent;
    border-radius: 50%;
    box-sizing: border-box;
    position: absolute;
    top: 0;
    transform: rotate(-135deg);
  }
  .circle_process .rightcircle {
    border-top: 20px solid green;
    border-right: 20px solid green;
    right: 0;
    -webkit-animation: circle_right 5s linear infinite;
  }
  .circle_process .leftcircle {
    border-bottom: 20px solid green;
    border-left: 20px solid green;
    left: 0;
    -webkit-animation: circle_left 5s linear infinite;
  }
  @-webkit-keyframes circle_right {
    0% {
      -webkit-transform: rotate(-135deg);
    }
    50%,
    100% {
      -webkit-transform: rotate(45deg);
    }
  }
  @-webkit-keyframes circle_left {
    0%,
    50% {
      -webkit-transform: rotate(-135deg);
    }
    100% {
      -webkit-transform: rotate(45deg);
    }
  }
</style>
<div class="circle_process">
  <div class="wrapper right">
    <div class="circle rightcircle"></div>
  </div>
  <div class="wrapper left">
    <div class="circle leftcircle" id="leftcircle"></div>
  </div>
</div>

大功告成。

4. 额外功能 #

我们已经实现了一个圆形进度条,利用这个,我们可以实现一个小闹钟:

function getTime() {
  var date = new Date();
  var second = date.getSeconds();

  var rightcircle = document.getElementById("rightcircle");
  var leftcircle = document.getElementById("leftcircle");
  var show = document.getElementById("show");

  show.innerHTML = second;

  if (second <= 30) {
    rightcircle.style.cssText = "transform: rotate(" + (-135 + 6 * second) + "deg)";
    leftcircle.style.cssText = "transform: rotate(-135deg)";
  } else {
    rightcircle.style.cssText = "transform: rotate(45deg)";
    leftcircle.style.cssText = "transform: rotate(" + (-135 + 6 * (second - 30)) + "deg)";
  }
}
getTime();
setInterval(function () {
  getTime();
}, 1000);
阅读(26838)
Simple Empty
No data