问题描述:今天到了公司,“德华”给我发来一段视频,是一个旋转的风车动画,看看有没有什么更好的实现方式么?脑爆就此开始……
目标:
小风车旋转时间为3s,间隔一段时间再旋转
首先拆解问题
分析问题:需要一个有间隔的无限循环动画,并需要有缓动函数
问题:1.css动画 2.有间隔 3.无限循环 4.缓动函数
当我们拆解完问题后可以想到目前的解决方案:
- 通过animation-delay属性添加延迟属性
- 设置整体动画时间(动画+延迟)在keyframes中将动画状态改为静止
通过监听animationEnd在动画执行结束后延迟一段时间再此执行动画
因为需要用css所以第三点就直接pass了,那么我们尝试一下前两个方案
方案一:通过animation-delay添加延迟属性
.rotate{
width:200px;
height:200px;
background:red;
animation:rotate 3s ease-in-out infinite both;
animation-delay:3s;//添加延迟属性
}
@keyframes rotate{
100%{
transform:rotate(1440deg)
}
}
复制代码
先用一个红色矩形模拟风车,并写了一个旋转4圈的的动画,旋转状态需要从静止缓慢开始,逐渐加快,最后再减速到停止,所以选用ease-in-out缓动函数,看下目前的效果:
可以看出应用animation-delay属性,这样延迟时间只再第一次动画开始有效,后面的每次动画并没有间隔时间,所以animation-delay的方案pass了
方案二:通过控制keyframes动画阶段停止达成延迟效果,假如间隔时间为3s,所以动画总时长需要设置成6s,前3s矩形为静止状态
.rotate{
width:200px;
height:200px;
background:red;
animation:rotate 6s ease-in-out infinite both;
}
@keyframes rotate{
0%{
transform:rotate(0deg)
}
50%{
transform:rotate(0deg)
}
100%{
transform:rotate(1440deg)
}
}
复制代码
这个效果看起来还可以,可以基本上满足我们的需求,但是这是假设3s的间隔,如果是60s的间隔动画看起来就会不协调,因为曲线函数影响的过程是动画的总长,所以动画旋转的过程就只能受到一部分曲线函数的效果,所以这个方案也不是完美方案
Css的障眼法
我们需要缓动函数时间和动画时间相等,那就意味着keyframes中只能存在旋转的动画;需要间隔,但是delay只能在首次生效;从单纯的css属性层面看来不能解决目前的问题了,所以我们需要一种办法骗过你的眼睛,“眼见不一定为真”
<div class="box">
<div class="rotate"></div>
</div>
<div class="front-box">
<div class="rotateone"></div>
</div>
复制代码
我们同时写两个元素相同的旋转元素,为了方便区分这里就用了不同的class,将下面的box元素设置上背景颜色,并将层级放到上面的box之上。这样看见的画面就只有一个静止的红色矩形,因为上面的元素被遮挡了。
此时,我们将上面box中的矩形设置上旋转动画,画面看起来也不会有任何变化,因为旋转元素还是在底层的
.rotate{
...
animation:rotate 3s ease-in-out infinite both;
}
@keyframes rotate{
100%{
transform:rotate(1440deg)
}
}
复制代码
但是如果此时我们将下面box的opacity设置为0,就能看见上面box中正在旋转的元素,那么,我们只需要在这个元素刚好旋转完一圈的时候将遮挡元素opacity设置为1,然后经过一定间隔时间,再将其设置为0,这样看起来就像这个动画间隔一段时间又继续运动一样。并且动画间隔时间和缓动函数不受时长的影响,只要间隔时间是旋转动画的倍数即可。
完整代码:
.rotate{
width:200px;
height:200px;
background:red;
margin:0 auto;
margin-top:100px;
animation:rotate 3s ease-in-out infinite both;
}
.box{
width:100%;
height:500px;
position:absolute;
left:0;
top:0;
}
.rotateone{
width:200px;
height:200px;
background:red;
margin:0 auto;
margin-top:100px;
}
.front-box{
width:100%;
height:500px;
position:absolute;
left:0;
top:0;
background:#fff;
z-index:2;
opacity:0;
animation:background 6s infinite linear both;
}
@keyframes rotate{
100%{
transform:rotate(1440deg)
}
}
@keyframes background{
0%{
opacity:0;
}
49%{
opacity:0;
}
50%{
opacity:1;
}
100%{
opacity:1;
}
}
复制代码
如果间隔时间太长,用1%会不精确,可以将百分比调整至0.1%为精度
预览地址:codepen.io/sanzang/pen…