本文作者:IMWeb 张颖 原文出处:IMWeb社区 未经同意,禁止转载
适逢元旦假期,妹子逛街吃火锅看电影陪女朋友之际,写出来的文章难免画风略微粗糙,但是这个动画的实现还是费了一番脑子的,话说程序猿之间交流并不需要过多解释,上代码就搞定。
首先说一下我们这个要实现的圆环进度动画,有三个特点:
1、背景是透明的,所以用遮挡实现的方法就不用考虑了;
2、圆环颜色是有透明度的,所以用两个半圆环实现大于180度的圆环效果不能有叠加部分;
3、最好用纯css3简洁的实现。
然后要备注下重点:
我们的动画效果要应用在移动端,尤其是有些性能较差的安卓手机,所以一定要考虑性能问题。
先上效果图:
对于不可用遮挡来实现的圆环动画效果,我们可以用两个半圆环的运动来组合,动画效果使用transition和transform实现。 圆环小于50%时:
圆环大于50%时,由两个不重叠的圆环组合而成:
所以对于大于50%的圆环旋转动画,是需要两段动画拼接的,左半边的圆环先旋转180度到右半边,右半边的圆环再旋转相应的度数至左半边,这里旋转角度不是固定的,需要根据具体进度确定,所以这种方案右半边的圆环旋转多少度是通过js赋值的,那么问题来了,当我们在pc上看到流畅的旋转动画时,在安卓手机上,两个半圆环动画的衔接处,有时差!不流畅!
思考下第一版方案失败的根本原因,就是整个圆环进度是由两个半圆环分别动画形成的,右侧圆环的旋转角度不是固定的,使用transition实现需要通过js动态添加旋转角度样式,js语句的执行使得两个圆环执行动画的时间差无法确定,在性能较差的安卓手机上会明显感觉到两个动画直接的衔接卡顿。
利用纯css控制两个半圆环动画的执行,让两个半圆环动画都固定旋转180度,时间差固定,我们要控制的就是可视区域的角度。 这里只讨论角度大于50%的情况,因为小于50%的情况无论用哪种方案都能实现。 上面我们讨论过,右半边不可见区域的圆环旋转到左半边时,整个左半边都是可见区域,所以我们旋转180度后当然能看见完整的半圆环,那我们尝试着根据我们需要的角度缩小左半边的可见区域不就可以了。(最后一幅图太困了,改天再补!)
具体来讲,我们实现右半边可见圆环用了两层,实现左半边可见圆环用了三层,两个圆环从左到右、从右到左分别旋转180度,最后我们可以完整的看到整个右半侧圆环,而左半侧的圆环因为还有一层遮挡,只能看到我们所需进度的相应角度。
<div class="my-circle" id="my-circle">
<div class="right-outter">
<div class="right-inner"></div>
</div>
<div id="left-outter-patch" class="left-outter-patch">
<div id="left-outter" class="left-outter">
<div id="left-inner" class="left-inner"> </div>
</div>
</div>
</div>
.my-circle {
position: relative;
width: 58px;
height: 58px;
}
.right-outter {
position: absolute;
width: 29px;
height: 58px;
top: 0;
right: 0;
overflow: hidden;
transform: rotate(180deg);
-webkit-transform: rotate(180deg);
}
.right-inner {
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 50px;
border-radius: 50%;
border: 4px solid rgba(113, 222, 130, 0.3);
clip: rect(0 58px 58px 29px);
}
.left-outter {
position: absolute;
width: 58px;
height: 58px;
top: 0;
left: 0;
overflow: hidden;
clip: rect(0 58px 58px 29px);
}
.left-inner {
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 50px;
border-radius: 50%;
border: 4px solid rgba(113, 222, 130, 0.3);
clip: rect(0 58px 58px 29px);
transform: rotate(180deg);
-webkit-transform: rotate(180deg);
}
.left-outter-patch {
position: absolute;
width: 58px;
height: 58px;
top: 0;
left: 0;
overflow: hidden;
clip: rect(0 58px 58px 29px);
}
.test-animation .right-inner {
transform: rotate(180deg);
-webkit-transform: rotate(180deg);
transition: transform 1s linear;
-webkit-transition: -webkit-transform 1s linear;
}
.test-animation .left-inner {
transform: rotate(360deg);
-webkit-transform: rotate(360deg);
transition: transform 1s linear 1s;
-webkit-transition: -webkit-transform 1s linear 1s;
}
所以动画是由css固定实现的,而左半侧的可视区域是由js代码控制的,这样无任何时差问题
var degree = 75;
document.getElementById("left-outter-patch").style.transform = "rotate(" + ((degree-50)*360/100) + "deg)";
document.getElementById("left-outter-patch").style.WebkitTransform = "rotate(" + ((degree-50)*360/100) + "deg)";
document.getElementById("left-outter").style.transform = "rotate(" + (180-(degree-50)*360/100) + "deg)";
document.getElementById("left-outter").style.WebkitTransform = "rotate(" + (180-(degree-50)*360/100) + "deg)";
document.getElementById("my-circle").className = "my-circle test-animation";