画图画腻了,大伙也不太爱看。这个估计也不爱看 随缘。今天换个口味,耍耍动画,就以 windows 的加载为例,手摸手一步一步来实现它。
0x0 效果预览

0x1 分析动画
- 有多个小球围绕中心作圆周运动
- 每个小球的运动方式相同,只是有不同延迟
- 好像也没啥了,简简单单
0x2 基本结构
既然是相同的动画,那么我们就从最基础的开始:先实现一个小球的运动。
写出如下HTML结构
<main>
<i></i>
</main>
main 为包裹层,你用 div也是一样,i标签为小球。
给出基本样式
CSS CODE
* {
margin:0;
padding:0;
}
html,
body {
height: 100vh;
background: #0077d5;
display: grid;
place-items: center;
}
main {
position: relative;
width: 20px;
height: 20px;
border: 1px dashed #fff;
border-radius: 50%;
i {
position: absolute;
inset: 0;
background: #fff;
border-radius: 50%;
}
}
上述代码,只是给定背景色、小球变为圆形,并且给中心点增加了个虚线效果(方便我们观察)
之所以看到是这个样子,是因为目前小球的位置是绝对定位了。
其中 inset: 0 是 top:0; left:0; right:0; bottom:0 的简写形式。
在此处含义就是让小球 i 与 容器 main 的大小相同。
0x3 动画制作
基本的结构已经搭建,下一步我们该着手动画了。
在写动画之前,我们仍需要思考一下该动画的运作方式:
- 我们当前小球与容器合体了,如何使用使小球位移到外围呢?
- 完成第一步后,如何让小球能够绕中心点作圆周运动呢?
从第一个问题着手:众所周知,css 中 的 transform 属性中的 translate 可以使元素位移。那我们就试一下
i {
// ...
transform: translate(100px,0);
}
此时小球果然位移到外围了,坐标是 x:100px y:0
该进行第二步了。那么怎样才能绕中心点运动呢?这也是本动画的难点所在。
还是和之前一样,既然整体暂时没有思路,那么我们就再拆开:拿一个位置点来思考。
圆的其中一个特性就是,圆周上任何一点到圆点的距离相等。
假设我们圆的半径为1,是从 水平位置 逆时针运动,那么小球每次与初始位置的夹角 为 θ,我们根据小学二年级学的三角函数可知 ,它的纵向坐标是不是可以直接表达成 sinθ ;横向坐标那就顺理成章表达为 cosθ。
\sin\theta = \cfrac{y}{1} \cos\theta = \cfrac{x}{1}
小球的实时位置坐标搞定了,接下来就是考虑动画了。
css动画,那必须少不了主角 animation ,搭配 transform 的 translate 属性,我们就可以让小球动起来
// ...
main {
--angle: 0;
i {
translate: calc(sin(var(--angle)) * 100px) calc(cos(var(--angle)) * 100px);
animation: rotate 3s infinite linear;
}
}
上述代码中,我们使用到了 calc计算函数,它可以根据数值自动来计算最终结果,这个非常有用,这里我们乘了一个系数 100,意思是将半径扩大到100px。另外,我们还定义了一个变量 angle,初始值为0deg,配合关键帧 keyframes 让它来实时改变。
@keyframes rotate {
0% {
--angle: 0deg;
}
100% {
--angle: 360deg;
}
}
想象很美好,然而不幸的是,小球并没有要动的意思,问题出在哪里呢?
在之前的几期中,我们已经熟练使用自定义属性(变量)来定义颜色,然而它并不能直接支持动画,因为CSS动画和过渡需要对属性的具体值进行插值。可以简单理解为 它是静态的,不能够动态改变。
为了解决这个问题,我们引出另一个黑科技 CSS Houdini API,其中有一个就是我们今天要用到的 @property。它的基本语法如下:
@property --property-name {
syntax: '<color>'; // 属性类型
inherits: false; // 是否允许继承
initial-value: #fff; // 默认值
}
关于它的详细描述,请参阅 MDN - @property
CSS Houdini API
CSS Houdini是一组低级API,它们允许开发者通过JavaScript直接与浏览器的CSS引擎进行交互,从而创建和控制自定义的CSS功能。Houdini 的目标是将一些浏览器内部的渲染流程开放给开发者,使得他们可以更灵活、更高效地创建复杂的视觉效果和动画,而不必等待浏览器原生支持这些特性。
OK,到此为止,知识点基本讲解完了,那么就直接使用起来,先让小球运动起来吧!
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
此时单个小球已经完美运动,将 linear 改为 ease-in-out 拥有更好的视觉效果

0x4 继续完善
好啦,单个小球的运动已经搞定,接下来就是继续将动画做完整,知识点都说完了,直接贴代码:
HTML
<main>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
</main>
我们将小球数量增加到了8个,但是好像预览结果与之前单个小球一样!产生这种原因是因为小球的位置在相同的地方,重合了。解决方法也很简单,给每一个小球增加一个动画延迟 animation-delay。写到这里有点累了,直接用sass弄一个:
i {
// ...
@for $i from 1 to 8 {
i:nth-child(#{$i}) {
animation-delay: #{$i * -0.12}s;
}
}
}
上述代码就是遍历给每个 li 添加不同的延迟,这里使用到负值,是为了让小球提前运动,避免等待。可以自己改成正值,对比一目了然,就不展开细说。延迟的基础系数可以自己调整到适合自己的,看效果:

0x5 再酷一点
到此位置,可以说是已经完成,但是,还能再酷一点。
我们对之前的sass稍作修改,让每个小球拥有不同的背景
@for $i from 1 to 9 {
i:nth-child(#{$i}) {
animation-delay: #{$i * -0.12}s;
background-color: #{hsl($i * 20 + 10, 80%, 60%, 85%)};
}
}
hsl()函数标记根据其色相 、饱和度 和明度 来表达 sRGB 颜色。
可选的 alpha 成分代表了颜色的透明度。——摘自MDN
再看眼最终效果

0x6 完整代码
点赞开启
HTML
<main>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
</main>
SASS
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
html,
body {
height: 100vh;
background: #0077d5;
display: grid;
place-items: center;
}
main {
position: relative;
width: 20px;
height: 20px;
border: 1px dashed #fff;
border-radius: 50%;
i {
position: absolute;
inset: 0;
background: #fff;
border-radius: 50%;
translate: calc(sin(var(--angle)) * 100px) calc(cos(var(--angle)) * 100px);
animation: rotate 3s infinite ease-in-out;
}
@for $i from 1 to 9 {
i:nth-child(#{$i}) {
animation-delay: #{$i * -0.12}s;
background-color: #{hsla($i * 20 + 10, 80%, 60%, 85%)};
}
}
}
@keyframes rotate {
0% {
--angle: 0deg;
}
95%,
100% {
--angle: 360deg;
}
}
本期结束,能看完的都是勇士!
图穷匕见,求赞,求认可 ![]()



