这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战
介绍
本期我们将用scss+svg去完成一款简单实用的加载动画——三色融合球,顾名思义,我们会做三个颜色的小球,进行变形旋转然后融合到一起最后循环往复这个操作。
我们先来直接看看做好的效果吧:
正文
1.基础结构
<div id="app">
<div class="loading">
<div class="loading-circle"></div>
<div class="loading-circle"></div>
<div class="loading-circle"></div>
</div>
</div>
#app{
width: 100%;
height: 100vh;
background-image: repeating-linear-gradient(90deg, hsla(196,0%,79%,0.06) 0px, hsla(196,0%,79%,0.06) 1px,transparent 1px, transparent 96px),repeating-linear-gradient(0deg, hsla(196,0%,79%,0.06) 0px, hsla(196,0%,79%,0.06) 1px,transparent 1px, transparent 96px),repeating-linear-gradient(0deg, hsla(196,0%,79%,0.09) 0px, hsla(196,0%,79%,0.09) 1px,transparent 1px, transparent 12px),repeating-linear-gradient(90deg, hsla(196,0%,79%,0.09) 0px, hsla(196,0%,79%,0.09) 1px,transparent 1px, transparent 12px),linear-gradient(90deg, rgb(255,255,255),rgb(255,255,255));
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.loading{
width: 200px;
height: 200px;
position: relative;
.loading-circle{
width: 60px;
height: 60px;
border-radius: 50%;
position: absolute;
left: 50%;
top: 50%;
margin: -30px 0 0 -30px;
}
}
结构很简单就是div#app我们将会铺满全屏又用repeating-linear-gradient绘制出了方格背景。然后div.loading做一个正方形性,里面会放三个用绝对定位于中央的小圆形。
2.小球动画
$colors:rgb(255, 208, 0),rgb(139, 203, 255),rgba(252, 96, 96, 0.945);
$duration:2s;
.loading-circle{
@for $i from 1 through length($colors) {
&:nth-child(#{$i}) {
background-color:nth($colors, $i);
animation: #{'circle-move-'+$i} $duration infinite;
}
}
}
@keyframes circle-move-1 {
0%,20%,100%{transform: translate(0,0) scale(1)}
40% {transform: translate(0,-18px) scale(.5)}
60% {transform: translate(0,-85px) scale(.5)}
80% {transform: translate(0,-85px) scale(.5)}
}
@keyframes circle-move-2 {
0%,20%,100%{transform: translate(0,0) scale(1)}
40% {transform: translate(-16px, 12px) scale(.5)}
60% {transform: translate(-90px, 65px) scale(.5)}
80% {transform: translate(-90px, 65px) scale(.5)}
}
@keyframes circle-move-3 {
0%,20%,100%{transform: translate(0,0) scale(1)}
40% {transform: translate(16px, 12px) scale(.5)}
60% {transform: translate(90px, 65px) scale(.5)}
80% {transform: translate(90px, 65px) scale(.5)}
}
这里就开始说重点了,我们先要用scss定义两个变量,一个是duration,它代表这我们一个动画的周期。
接下来,我们通过scss的@for方法进行遍历,去设置这三个小球的颜色和动画,这里注意scss用nth(i)这个方式去获取数组下的值,但是$i的下标与js不同,不能等于0,如果@for从0开始则会就直接会报错。
至于动画,就是让他三个球在某个时间段缩小从中间偏移出去,到了一定程度再回来循环往复,详细的就直接看代码,这里不再过多赘述。
3.改变顺序
.loading-circle{
@for $i from 1 through length($colors) {
&:nth-child(#{$i}) {
background-color:nth($colors, $i);
animation: #{'circle-move-'+$i} $duration infinite,change-z-index #{$duration * length($colors)} -#{$duration * $i} infinite;
}
}
}
@keyframes change-z-index{
0%,100%{
z-index: 3;
}
33.33%{
z-index: 2;
}
66.66%{
z-index: 1;
}
}
刚才也看到了,我们的三个小球因为是绝对定位,所以每当聚集在一起的时候总是最下面的会遮盖其他小球。上面用的方法就是通过z-index去根据周期设置优先级,然后就可以不停的改变了。
4.旋转动画
.loading{
animation: rotate $duration infinite;
}
@keyframes rotate{
0%,60%{
transform: rotate(0deg);
}
80%,100%{
transform: rotate(360deg);
}
}
此时,我们界面还不够炫,还要让他们三个在分开的时候转起来,上面的代码就是每当小球一个周期完成,我们就让他旋转一次,当然这个动画直接加在div.loading上就行,不要粗心的加在小球上。
5.融合处理
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="mix">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -7"/>
</filter>
</defs>
</svg>
.loading{
filter: url(#mix);
}
我们的题目是要怎么让他们融合。很多小伙伴会相信会想到用css的filter的contrast+blur去完成,但是这样不行,会污染我们想要的颜色,所以这里用svg写了一套滤镜,这里说一下,svg的filter元素作用是仅作为滤镜操作的内容,本身没有什么可以呈现的内容。使用也是通过css的filter用url去引入使用。上面的代码就是做了一个模糊识别处理,这段代码可以通用哦。这样,就大功告成了~
写到这里我们就完成了这整个动画,在线演示。
结语
不知道学完这个案例你是否有收获,反正我实现它的时候,感觉scss书写真的太好用,寥寥几句就可以完成很多事,而且非常优雅也便于维护。再就是配合svg的滤镜虽然非常晦涩,但功能真是炒鸡强大,感觉要走的路还有很多,还会有更多的效果等着我们去想象和挖掘。还等什么?一起也来探索一下吧。