前言

在网上看到了这种加载特效,也尝试自己写一个

CSS实现加载特效1_transform

实现思路

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;
        }

效果

CSS实现加载特效1_动画_02

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