前言
在网上看到了这种加载特效,也尝试自己写一个
实现思路
1.写一下基础的dom
<div class="container">
<div class="loading">
</div>
</div>
container和页面一样大小
loading装载加载元素
2.内部dom
用js在loading中增加20个span元素当做圆点的容器
let loading = document.querySelector('.loading');
for(let i=1;i<=20;i++){
let span = document.createElement('span');
span.style.setProperty('--i',i);
loading.appendChild(span)
}
创建span元素,增加css变量--i,方便后面使用css变量来做区分
3.基础样式
经过上面两步,页面的dom元素就齐备了
下面我们将基本的样式写出来
:root{
--span-size:20px;
}
body{
inset: 0;
margin:0;
}
.container{
height: 100vh;
width: 100vw;
background-color: rgb(9, 5, 46);
display: flex;
justify-content: center;
align-items: center;
}
.container .loading{
width: 180px;
height: 180px;
position: relative;
}
.loading span{
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
上面的css主要实现了 :
- 定义了css变量,用来规定小圆点的初始尺寸
- 将body的padding、margin归零
- 将container元素尺寸同浏览器视口一致,并设置内部元素水平和垂直居中,就是让加载元素居中
- 设置loading加载元素容器的尺寸
- 设置loading内部的span元素尺寸为填满,并且所有span重叠在一起
4.样式效果
通过上面的效果图可以看到小圆点是围绕中线展开的,我们可以使用transform的rotate
首先我们设置span中的伪元素before,使之位于span的左上角并设置宽高、背景色、圆角、阴影等
然后旋转span元素
.loading span::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: var(--span-size);
height: var(--span-size);
border-radius: 50%;
background-color: aquamarine;
box-shadow: 0 0 10px aquamarine,
0 0 20px aquamarine,
0 0 30px aquamarine,
0 0 40px aquamarine,
0 0 100px aquamarine;
}
效果
5.颜色变换
我们写一个动画,然后利用filter的hue-rotate色相旋转来更改颜色
@keyframes changeBG {
from{
filter: hue-rotate(0deg);
}
to{
filter: hue-rotate(360deg);
}
}
然后把container加上上述的动画
.container{
height: 100vh;
width: 100vw;
background-color: rgb(9, 5, 46);
display: flex;
justify-content: center;
align-items: center;
animation: changeBG 10s linear infinite;
}
这样就完成颜色变化
6.圆点缩放
圆点的缩放我们也通过关键帧@keyframes来实现,在关键帧中加上css3的2D转换中的scale
@keyframes anim {
0%{
transform: scale(1);
}
80%,100%{
transform: scale(0);
}
}
然后将动画加入到span的伪类before中
.loading span::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: var(--span-size);
height: var(--span-size);
border-radius: 50%;
background-color: aquamarine;
box-shadow: 0 0 10px aquamarine,
0 0 20px aquamarine,
0 0 30px aquamarine,
0 0 40px aquamarine,
0 0 100px aquamarine;
animation: anim 2s linear infinite;
}
这样圆点就达到了变色和缩放
7.时间差
但是目前还没完成,因为圆点都是同时放大缩小,没有差异
如果能让圆点的动画起始时间依次递增,就能达到上图的效果了
我们可以利用一开始写的--i变量,然后设置每个span伪类before的动画开始时间属性animation-delay就可以啦
animation-delay: calc(var(--i) * 0.1s);
这行代码的意思就是让所在元素的动画开始时间延迟多少秒,然后用calc计算每个元素的时间递增,就ok了
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加载特效</title>
</head>
<body>
<div class="container">
<div class="loading">
</div>
</div>
<script>
let loading = document.querySelector('.loading');
for(let i=1;i<=20;i++){
let span = document.createElement('span');
span.style.setProperty('--i',i);
loading.appendChild(span)
}
</script>
<style>
:root{
--span-size:20px;
}
body{
inset: 0;
margin:0;
}
.container{
height: 100vh;
width: 100vw;
background-color: rgb(9, 5, 46);
display: flex;
justify-content: center;
align-items: center;
animation: changeBG 10s linear infinite;
}
.container .loading{
width: 180px;
height: 180px;
position: relative;
}
.loading span{
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
transform: rotate(calc(var(--i) * 18deg));
}
.loading span::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: var(--span-size);
height: var(--span-size);
border-radius: 50%;
background-color: aquamarine;
box-shadow: 0 0 10px aquamarine,
0 0 20px aquamarine,
0 0 30px aquamarine,
0 0 40px aquamarine,
0 0 100px aquamarine;
animation: anim 2s linear infinite;
animation-delay: calc(var(--i) * 0.1s);
}
@keyframes changeBG {
from{
filter: hue-rotate(0deg);
}
to{
filter: hue-rotate(360deg);
}
}
@keyframes anim {
0%{
transform: scale(1);
}
80%,100%{
transform: scale(0);
}
}
</style>
</body>
</html>
总结
这个实现本身并不复杂,只是需要思考实现思路需要一些巧思
主要也是用到了transform中的特性以及关键帧@keyframes