沿环形路径转动的动画
今天利用CSS实现一种沿着环形路径转动的动画。为了便于演示,我们让一个头像图片沿着环形路径转动。
首先是一个img标签,用来保存头像图片,外面嵌套一个div用来设置背景。
<div class="path">
<img src="test.jpg" class="avatar">
</div>
然后设置基本的样式:
.path{
width: 200px;
height: 200px;
margin:20px auto;
padding: 20px;
border-radius: 50%;
background: #fb3;
}
.avatar,{
width: 40px;
height: 40px;
margin: 0 auto;
display: block;
border-radius: 50%;
border: 1px dashed black; /*为了便于观察旋转,添加虚线边框*/
overflow: hidden;
}
.avatar-a>img{
display: block;
width: inherit;
}
最后为图片添加旋转动画:
@keyframes spin{
to { transform: rotate(1turn); }
}
.avatar{
animation: 6s spin infinite linear;
transform-origin: 50% 100px;
}
刷新页面:

虽然图片已经能够沿着环形路径转动了,但是图片自身也在旋转。为了让图片能够沿着环形转动,同时保证图片保持原来的朝向,可以用下面这两种方式:
既然图片本身也在旋转,那可以尝试在图片的外层嵌套一个div,然后让这个div反向旋转,从而把内层的图片旋转效果给抵消掉。这也是之前经常用到的一种方法。
修改HTML代码结构:
<div class="path">
<div class="avatar-a">
<img src="test.jpg">
</div>
</div>
下面就利用到上篇文章提到的animation-direction,图片外层的div保持旋转,然后设置内部img的animation-direction为相同的动画特效,但是最后让animation-direction反转。
@keyframes spin{
to { transform: rotate(1turn); }
}
.avatar-a{
animation: 6s spin infinite linear;
transform-origin: 50% 100px;
}
.avatar-a>img{
animation: inherit;
animation-direction: reverse;
}

much nicer!
问题虽然得到解决,但是修改了HTML结构。下面这种方式能够在保持原来HTML代码结构不变的情况下解决自身旋转问题。在提出这种方法之前,要首先了解下transform-origin。其实:
每个transform-origin都可以被两个translate()模拟出来
比如下面这个两端代码是等效的:
transform: rotate(30deg);
transform-origin: 100px 50px;
transform: translate(100px,50px),
rotate(30deg),
translate(-100px,-50px);
transform-origin: 0 0;
具体过程如下图:

于是,我们可以把刚才的spin动画拆分:
@keyframe spin{
from{
transform: translate(50%,100px)
rotate(0turn)
translate(-50%,-100px);
}
to{
transform: translate(50%,100px)
rotate(1turn)
translate(-50%,-100px);
}
}
对于自身的反向旋转进行拆分:
@keyframe spin{
from{
transform: translate(50%,50%)
rotate(1turn)
translate(-50%,-50%);
}
to{
transform: translate(50%,50%)
rotate(0turn)
translate(-50%,-50%);
}
}
然后把img外部嵌套的div去掉,把这两个动画合并,直接用在img上,这样既保持了原有的HTML代码结构,也解决了图片的自旋转问题。最终代码如下:
HTML:
<div class="path">
<img src="test.jpg" class="avatar-b">
</div>
CSS:
@keyframes spin-b{
from{
transform: translate(50%,100px)
rotate(0turn)
translate(-50%,-100px)
translate(50%,50%)
rotate(1turn)
translate(-50%,-50%);
}
to{
transform: translate(50%,100px)
rotate(1turn)
translate(-50%,-100px)
translate(50%,50%)
rotate(0turn)
translate(-50%,-50%);
}
}
.avatar-b{
animation: 6s spin-b infinite linear;
}
也可以把一个关键帧的水平位移抵消,以精简代码:
@keyframes spin-b{
from{
transform: translateY(100px) translateY(-50%)
rotate(0turn)
translateY(-100px) translateY(50%)
rotate(1turn);
}
to{
transform: translateY(100px) translateY(-50%)
rotate(1turn)
translateY(-100px) translateY(50%)
rotate(0turn);
}
}

much nicer!