css3环形进度--巧用clip

945 阅读3分钟

前言

最近在研究微信小程序的知识,在预研的过程中发现原生小程序缺少很多组件,那么环形进度组件也在其中。以前接触过Element-ui的环形进度组件,可是它是基于svg来制作的。在最新版的小程序中虽然支持了canvas,但是它没有支持svg,所以想在小程序中使用svg来实现这个环形进度组件是不可能的了,那么有什么办法能实现这个呢?微信小程序支持了很多css3的特性,我打算用css3来实现这个环形进度条。

技术重点 clip 和 transform:rotate

clip

Clip属性在W3C官网是这样进行描述的:“通过对元素进行剪切来控制元素的可显示区域,默认情况下,元素是不进行任何剪切的,但是也有可能剪切区域也显示的设置了clip属性”。 使用语法如下:

.selector {
    clip: <shape> | auto | inherit
}   

clip属性只接受三个不同的属性值:

  • shape:shape是一个函数功能,当使用仅使用rect()属性;
  • auto:这是一个默认值,clip设置auto值和没有进行剪切是一样的效果;
  • inherit:继承父元素的clip属性值。

重点说说rect()函数

接下来我们来看rect()使用方法。rect()需要设置四个值:top, right, bottom和left。他们之间需要用逗号隔开,而且rect()属性值和margin、padding以及bodrder具有一样的标准,遵循TRBL顺时针旋转的规则。

 clip: rect(top,right,bottom,left);

rect()参数

  • top和bottom指定偏移量是从元素盒子顶部边缘算起;
  • left和right指定的偏移量是从元素盒子左边边缘算起(包括边框)。 如下示意图:

使用前提:

1.clip属性只能在元素设置了“position:absolute”或者“position:fixed”属性起作用

2.值不能设置为百分比

3.在动画设置过程里不能使用auto,使用auto没有动画效果

transform:rotate

这个相对就比较好理解,主要是用来给元素进行旋转的。这个就不过多介绍。

环形进度的思路

这里主要用到的是CSS中的clip属性,将一个正方形裁剪后只显示右侧一半,但是仍然以正方形中心为圆心来旋转,来实现需要的角度。

clip: rect(0rpx, 46rpx, 92rpx, 0rpx);

这样最上面那个进度条就可以由以下三部分叠加,在最上面再叠加一个小一号的白色圆形,最外层加上圆角后就可以实现。(下图中红线示例了最外层的圆角以及最上层叠加的白色圆形位置)

用到蓝色圆环小于180度的情况下,需要把背景色和前景色对调。

具体实现

下面的代码是html的代码,如果换成微信小程序,只需要把rpx单位换成px即可。 直接看代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>

.circle-process{
	position: relative;
	width: 300px;
	height: 300px;
	display: flex;
    justify-content: center;
    align-items: center;
	border-radius: 100%;
	overflow: hidden;
}
.circle-process-inner{
	width: 260px;
	height: 260px;
	background-color: #fff;
	z-index: 3;
	border-radius: 100%;
}
.circle-sk1,.circle-sk2{
	position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip: rect(0px, 150px, 300px, 0px);
}
.circle-sk1{
	z-index: 1;
}
.circle-sk2{
	z-index: 2;
}

.circle-bg1 {
    background: #4886ff;
}

.circle-bg1 .circle-sk1, .circle-bg1 .circle-sk2 {
    background: #ccc;
}

.circle-bg2{
	background: #ccc;
}

.circle-bg2 .circle-sk1, .circle-bg2 .circle-sk2 {
    background: #4886ff;
	transform: rotate(180deg);
}



</style>
<body>

	<!--  进度小于50%时(也就是角度大于180度) 使用circle-bg1 否则使用circle-bg2  -->
	<!--  进度小于50%时 rotate的值计算公式是:(360 * percent / 100) - 180)  -->
	<!--  进度大于50%时 rotate的值计算公式是:(360 * (percent - 100) / 100)  -->
	<div class="circle-process circle-bg1">
		<div class="circle-sk1"></div>
		<div class="circle-sk2" style="transform: rotate(-90deg);"></div>
		<div class="circle-process-inner"></div>
	</div>


	<div class="circle-process circle-bg2">
		<div class="circle-sk1"></div>
		<div class="circle-sk2" style="transform: rotate(-72deg);"></div>
		<div class="circle-process-inner"></div>
	</div>


</body>
</html>


vue2的demo

html代码如下:

<div id="app">
    <div class="circle-process circle-bg1" :class="{'circle-bg1':percent<50,'circle-bg2':percent>50}">
            <div class="circle-sk1"></div>
            <div class="circle-sk2" :style="rotate"></div>
            <div class="circle-process-inner"></div>
    </div>
  </div>

script的代码如下:

var app = new Vue({
  el: '#app',
  data: {
    percent:0,
  },
  computed:{
    rotate:function(){
      let r= -180;
      if(this.percent <= 50){
        r = (360 * this.percent / 100) - 180
      }else{
        r = (360 * (this.percent - 100) / 100)
      }
      return "transform: rotate("+r+"deg)"
    }
  }
})

然后动态的设置percent即可。 上述代码并没有封装成组件。只是一个可执行的demo,想封装成组件的,也可以参考这个