分享一个简单的loading效果,如下:
本案例来源于 Temani Afif on CodePen[1],略有修改
仔细观察,主要有两个动画
- 小球的运动
- 背景的变化
看似有点复杂,其实换个角度,实现要比想象的容易很多,也非常巧妙,一起看看吧
一、整体思路
如果按照正常的思路,可能会做两个动画,小球的动画还好,只是方位的变化,但是背景就麻烦了,除了颜色的变化,还有角度的变化,该如何实现呢?
其实换一下角度,多观察几遍,将整个视野反过来,你会发现,小球的背景相对于整个画布是静止的,也就是说,背景其实没有变化,小球只是挖了一个孔,这个孔在运动,示意效果如下:
提到挖孔,可以想到遮罩(CSS Mask)。关于遮罩,这个技巧非常实用,之前在多篇文章中都有用到
- 一个有意思的CSS图片hover效果[2]。
- CSS 如何实现羽化效果?[3]。
- 别用图片了,CSS 遮罩合成实现带圆角的环形 loading 动画[4]。
- CSS mask 实现鼠标跟随镂空效果[5]。
- CSS 实现Chrome标签栏的技巧[6]。
- CSS 实现优惠券的技巧[7]。
所以,如果想到了这一点,下面的实现就很简单了,一个4种颜色的背景和一个运动的黑色遮罩
二、背景的绘制
相信大家对这个背景都很熟悉,经常在CSS绘制三角形的时候看到这个原理图,这里同样也可以用border来实现。
div{
width: 0;
border: 60px solid;
border-color: #2196F3,#F44336,#4CAF50,#FFC107
}
这样就得到所需要的图案。
当然,除了这种方式,还可以采用锥形渐变来绘制。
有关锥形渐变的技巧,可以参考之前这几篇文章
- 锥形渐变只能画圆锥吗?conic-gradient 10大应用举例[8]。
- 纯CSS渐变绘制 Chrome 图标[9]。
- CSS & SVG 绘制写作网格线的3种方式[10]。
- CSS 实现切角效果[11]。
- CSS 绘制一个时钟[12]。
- CSS 实现透明方格的 3 种方式[13]。
实现也很简单,起始角度是45deg,每 1/4换一种颜色。
div{
width: 120px;
height: 120px;
background: conic-gradient(from 45deg,#2196F3 25%,#F44336 0 50%,#4CAF50 0 75%,#FFC107 0);
}
也能得到和上面完全相同的背景。
三、镂空小球的绘制和运动
接下来需要通过 CSS MASK来绘制小球。很简单,就是一个从实色到透明的径向渐变。
div{
...
-webkit-mask: radial-gradient(closest-side circle,#000 99%,#0000 100%) left/40px 40px no-repeat
}
注意,这里使用了关键词closest-side,表示最近的边,好处是可以根据背景尺寸直接控制圆的大小,默认值是farthest-side,其他选项详细如下:
关键字 | 描述 |
closest-side | 渐变中心距离容器最近的边作为终止位置。 |
closest-corner | 渐变中心距离容器最近的角作为终止位置。 |
farthest-side | 渐变中心距离容器最远的边作为终止位置。 |
farthest-corner(默认值) | 渐变中心距离容器最远的角作为终止位置。 |
当然,对于完全对称的容器,closest-* 和 farthest-*是完全相同的,各自的区别如下所示:
可以得到这样的效果,其余部分已经被裁剪掉了。
最后只需要改变遮罩的位置就行了,动画关键帧如下:
@keyframes load {
25% {-webkit-mask-position: top }
50% {-webkit-mask-position: right }
75% {-webkit-mask-position: bottom}
}
这样就实现了文章开头的效果:
完整代码如下:
.loader {
width: 120px;
height: 120px;
background: conic-gradient(from 45deg,#2196F3 25%,#F44336 0 50%,#4CAF50 0 75%,#FFC107 0);
-webkit-mask: radial-gradient(50% 50%,#000 96%,#0000) left/35% 35% no-repeat;
animation: load 2s infinite;
}
@keyframes load {
25% {-webkit-mask-position: top }
50% {-webkit-mask-position: right }
75% {-webkit-mask-position: bottom}
}
完整代码可以查看以下任意链接:
- CSS dot loader (juejin.cn)[14]。
- CSS dot loader (codepen.io)[15]。
- CSS dot loader (runjs.work)[16]。
四、总结一下
总的来说实现非常简单,都是一些比较常规的绘制方式,但是思路却非常巧妙,通过改变 MASK 遮罩的位置来实现小球的背景位置变化,下面简单总结一下
- 整体思路其实是背景不动,挖孔在动。
- 背景可以通过不同颜色的边框实现。
- 背景还可以通过锥形渐变实现。
- 圆形挖孔其实就是径向渐变的遮罩。
- 通过动画改变遮罩的位置。
另外,关于锥形渐变和遮罩在本文介绍的并不多,但是引入了之前很多相关文章,有兴趣的可以回顾一下,很多非常实用的案例。
参考资料
[1]Temani Afif on CodePen: https://codepen.io/t_afif/details/NWyOdgv。
[2]一个有意思的CSS图片hover效果: https://juejin.cn/post/7233177170489688120。
[3]CSS 如何实现羽化效果?: https://juejin.cn/post/7176094306124431421。
[4]别用图片了,CSS 遮罩合成实现带圆角的环形 loading 动画: https://juejin.cn/post/7217731969307328571。
[5]CSS mask 实现鼠标跟随镂空效果: https://juejin.cn/post/7033188994641100831。
[6]CSS 实现Chrome标签栏的技巧: https://juejin.cn/post/6986827061461516324。
[7]CSS 实现优惠券的技巧 : https://juejin.cn/post/6945023989555134494。
[8]锥形渐变只能画圆锥吗?conic-gradient 10大应用举例: https://juejin.cn/post/7212101184709247033。
[9]纯CSS渐变绘制 Chrome 图标: https://juejin.cn/post/7230603857033986109。
[10]CSS & SVG 绘制写作网格线的3种方式: https://juejin.cn/post/7186524908464111676。
[11]CSS 实现切角效果: https://juejin.cn/post/7087774534996066334。
[12]CSS 绘制一个时钟: https://juejin.cn/post/7090364550809124901。
[13]CSS 实现透明方格的 3 种方式: https://juejin.cn/post/7072175448301994020。
[14]CSS dot loader (juejin.cn): https://code.juejin.cn/pen/7235176585551167546。
[15]CSS dot loader (codepen.io): https://codepen.io/xboxyan/pen/VwEVdyR。
[16]CSS dot loader (runjs.work): https://runjs.work/projects/b90d34e7833849d6。