深入挖掘CSS让前端飞程序员

加载效果 会这几个就够了

2018-02-26  本文已影响32人  果汁凉茶丶

  网络上有很多关于加载效果的文章,大部分都比较重复也比较简单,比较累赘。这里我总结了几种非常常用的,和一款最常见的长短变化的圆环加载效果。有不同想法的人,希望能与你交流

# 华为手机的加载动效

  先来看看我们要做一个什么样的东东:

刚开始时 加载到一半时

分析】华为手机的加载效果由五个大小不同的点组成,一开始时是一个点(五个点重叠),然后大点先出发,间隔一定时延 下一个点出发;转完一圈后,回到起始位置,等待所有的点都回到起始位置后准备开始下一次动作。

  或许听起来有点复杂,但其实很简单,五个点,如果单独只看一个点,就得到了网络上常说的另一个效果

  先看这个例子:蓝色的球是运动的点,白色圆环是球运动的轨迹,整体形成了星球环绕的感觉。这个怎么实现?实现了它,华为手机的loading效果也就迎刃而解了。

  实现的关键点,在于如何制作圆球绕圈转动,这里使用了一个技巧,即绘制如下图效果

<div>
  <p></p>
</div>
div {
  width: 10px;
  height: 50px;
  background: lightblue;
}
p {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: red;
}

  因为元素有先上后下,先左后右的排列规则,我们可以很容易得到如上效果。接着为父元素div添加转动动画,浅蓝色div绕着中心点转动,形成红色圆圈绕圈转动的直观感受。接着,去掉div颜色,再添加一个圆环就可以实现上面星球环绕的loading效果。

如何从星球环绕效果过渡到华为手机loading效果?上面已经说过,得到一个点的绕圈运动后,增加五个直径不同的点延迟出发即可,具体实现如下:

<div class="wrap">
    <div class="fs-ball-holder fs-ball-1">
        <div class="fs-ball-a"></div>
    </div>
    <div class="fs-ball-holder fs-ball-2">
        <div class="fs-ball-b"></div>
    </div>
    <div class="fs-ball-holder fs-ball-3">
        <div class="fs-ball-c"></div>
    </div>
    <div class="fs-ball-holder fs-ball-4">
        <div class="fs-ball-d"></div>
    </div>
    <div class="fs-ball-holder fs-ball-5">
        <div class="fs-ball-e"></div>
    </div>
</div>
.fs-ball-holder {
    position: absolute;
    width: 1rem;
    height: 4rem;
    left: 2rem;
}
.fs-ball-a, .fs-ball-b, .fs-ball-c, .fs-ball-d, .fs-ball-e {
    position: absolute;
    border-radius: 50%;
    background: #3d77e0;
}
.fs-ball-a {
    top: -.75rem;
    left: -.3rem;
    width: .7rem;
    height: .7rem;
}
...

.fs-ball-1 {
    animation: fs-ball-loading 1.5s .1s ease infinite;
}
.fs-ball-2 {
    animation: fs-ball-loading 1.5s .2s ease infinite;
}
...

注意点】避免篇幅过长,省略去了部分可复制性CSS代码,请自行添加。
(1)设置大小不同的点的时候,由于CSS元素的排列规则是从上到下,从左到右,造成所有点左上角对齐,在动画执行(点开始出发,和点回到出发位置)时会有拖尾感,因此需要对每个点挪动到中心对齐,由于点的display: absolute,这个很容易使用top left实现。
(2)同样点大小造成的问题,因为点的大小不同,如果设置每个点出发的时延一致,会造成点和点之间的距离不一致,也会影响整体效果,因此需要适当调节每个点出发时延大小。
(3)要实现先转好的点回到起始位置需要等待后面的点回来,动画可以分成两个step执行完成,也可以如上设置首个点的出发延迟,造成前后两次绕圈的间隔感。但采用后者有个弊端,如果加载本身时间就很短,会出现遮罩层出现了,但动画还没执行的情况。请酌情使用。

# 网页常用加载动效

  这款加载效果非常简单,又非常实用,如下

  都知道,制作一个圆环只需要用圆角为50%的正方形加上边框,再设置box-sizing即可,那这缺了一个角的圆环,是很少了一个角的border的圆环吗?答案是否定的。

div {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border-top: solid 5px #2a2fa0;
    border-right: solid 5px #2a2fa0;
    border-left: solid 5px #2a2fa0;
}

  很明显这种效果不是我们想要的,为什么会发生这个现象?该例我们设置了一个圆外加边框,因此CSS优先生成内部的圆图形,为了防止效果的突变,CSS会为没有设置边框的边自动绘制渐变边框。或许你会说,加box-sizing:border-box试试?然而并没有用,box-sizing: border-box只是将圆圈图形规范到边框上了而已,并没有真正解决边框渐变问题。

  要解决这个问题其实很简单,将某个边框隐藏即可。

  CSS通用的隐藏有两种办法,一种是设置透明opacity,一种是设置display:none。后者常用在整个选择器中,在这里并不是适用。只能用透明。但是border属性又没有类似border-top-opacity属性怎么办?

  大家不要忘了设置颜色除了十六进制方法外,还有 rgba(),这个 a 就是指的透明度。
  到此为止,我们只要如下设置即可:

div {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border-top: solid 3px #2a2fa0;
    border-right: solid 3px rgba(42,47,160,0);
    border-bottom: solid 3px #2a2fa0;
    border-left: solid 3px #2a2fa0;
    animation: fs-ring-loading 1.5s linear infinite;
}

@keyframes fs-ringball-loading {
    100% {
        transform: rotate(360deg);
    }
}

 

# Ubuntu 开机加载动效

  ubuntu的开机加载动效如下所示

上半程
下半程
分析】该加载效果先由五个白色的点,上半程一个个逐渐变成蓝色,在下半程再一个个逐渐变成白色,如此往复。值得注意的是,下半程的蓝色编程白色过程是突变过程,关于这点请继续往下看

  该例的实现也很简单,没有什么技巧可言,设置五个点,用动画控制颜色变化

<div class="wrap ball-light-wrap">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
</div>
.ball-light-wrap span {
    display: inline-block;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    margin-right: .5rem;
    background-color: #ffffff;
    animation: fs-balllight-load 6s linear infinite;
}
.ball-light-wrap span:nth-child(1){ animation-delay: .5s; }
.ball-light-wrap span:nth-child(2){ animation-delay: 1s; }
...

@keyframes fs-balllight-load {
    0%, 49.9% {
        background-color: #3d77e0;
    }
    50%, 100% {
        background-color: #ffffff;
    }
}

  关于动画中step,用0%,49.9%50% ,100% 是实现将渐变修改为突变的一种常见的做法。因为动画有渐变过渡模式,用这种方式我们将渐变过程锁定到49.9%50%中。
 

# Windows 开机加载动效

  相信大家都见过windows的加载效果,这里简要形容一下:





  五个点先快速从底部钻出来,转两圈绕回到底部隐藏,稍作间隔后,准备下一次执行。其中,在底部转动速度比在顶部的速度要快。
  和华为的loading效果大同小异,主要是动画上的区别,这里需要有出现,然后绕两圈,最后再隐藏的效果。html和圆圈的css相信大家都会了,来看看动画step怎么实现

@keyframes fs-ballhide-load {
    0% {
      opacity: 1;
      transform: rotate(0);
    }
    30% {
      transform: rotate(360deg);
    }
    60% {
      opacity: 1;
      transform: rotate(720deg);
    }
    60.1% {
      opacity: 0;
    }
    100% {
      opacity: 0;
      transform: rotate(720deg);
    }
}

 

# 波浪加载动效

  这款动效也很常用,一般出现在个人网页或公司APP中

初始状态 执行过程

  实现的思路就是,绘制基本元素即五个矩形,通过CSS transform: scaleY() 来实现在纵向上的拉伸,与此同时修改被拉伸元素的颜色即可。很简答,直接上代码

<div class="wrap lineboth-wrap">
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>
.lineboth-wrap span {
  width: .5rem;
  height: 1.5rem;
  margin-right: .3rem;
  background: #3d77e0;
  animation: fs-lineboth-load 1s ease-in-out infinite;
}
.lineboth-wrap span:nth-child(2) { animation-delay: .1s; }
.lineboth-wrap span:nth-child(3) { animation-delay: .2s; }
.lineboth-wrap span:nth-child(4) { animation-delay: .3s; }
.lineboth-wrap span:nth-child(5) { animation-delay: .4s; margin-right: 0; }

@keyframes fs-lineboth-load {
  25% {
    transform: scaleY(2.5);
    background-color: antiquewhite;
  }
  50% {
    transform: scaleY(1);
    background-color: #3d77e0;
  }
}

  关于波浪加载,还有一种效果如下


填坑】或许你在制作的时候会遇到一个问题,就是在动画执行过程中,感觉每一个小块都不停的在跳动,严重整体加载效果。我曾看过网络上的某篇文章,它也有这个问题但并没有给出解决方案。

  出现这个问题的根本原因是因为在缩放过程中,元素大小发生变化,由于CSS的定位规则,当元素加长时会往下撑开,又因为五个元素都在变化,高度无法形成一致,因此就有了跳动感。

办法】要解决这个问题有两种办法,一种是设置每个小方块为绝对定位,脱离普通文档流。二是治本,设置辅助块来实现每一个方块的高度与辅助块高度之和固定不变。第一种比较简单,相信大家差不多都能做出来,来说说第二种

  所谓的辅助块,并不需要去设置一个divspan。因为是底部对齐,使用margin-top配合动画step可。

.line-wrap span {
    display: inline-block;
    width: .5rem;
    height: 1rem;
    margin-top: 2rem;
    border-radius: .25rem;
    margin-right: .3rem;
    background-color: #ffffff;
    animation: fs-line-load 1s linear infinite;
}

@keyframes fs-line-load {
  50% {
    height: 2rem;
    margin-top: 1rem;
    background-color: #3d77e0;
  }
  100% {
    height: 1rem;
    margin-top: 2rem;
    background-color: #ffffff;
  }
}

 

# 齿轮加载动效

  先看看效果图

分析】齿轮加载的关健点在于如何实现绕成一圈的轮牙,然后对每一个轮牙做颜色渐变即可。原理比较简单,实现上有比较多的细节需要计算。

实现办法】齿轮的实现有两种办法:
(1)绘制如图八个轮牙,借助transform:rotate()对需要倾斜放置的轮牙做旋转,用position:absoluteleft right做位置偏移。这种办法数据计算偏多。
(2)这种办法稍微简单些,原理同华为手机loading效果模块讲解的相同,绘制一个父元素div用来承载轮牙,在div的两头绘制两个轮牙,其他轮牙同理。这种该办法我们只需要管理父元素div的旋转角度即可。

  这里给出我的一个方案1的实现案例,html部分和上例类似。

.geer-wrap span {
  display: inline-block;
  width: 1rem;
  height: .5rem;
  border-top-left-radius: .25rem;
  border-bottom-left-radius: .25rem;
  background-color: #ffffff;
  position: absolute;
  animation: fs-geer-load 1.04s linear infinite;
}
.geer-wrap span:nth-child(1) {
  left: 0;
  top: 50%;
  animation-delay: .13s;

}
.geer-wrap span:nth-child(2) {
  left: 10%;
  top: 20%;
  transform: rotate(45deg);
  animation-delay: .26s;
}
.geer-wrap span:nth-child(3) {
  left: 40%;
  top: 10%;
  transform: rotate(90deg);
  animation-delay: .39s;
}
.geer-wrap span:nth-child(4) {
  right: 10%;
  top: 20%;
  transform: rotate(135deg);
  animation-delay: .52s;
}
.geer-wrap span:nth-child(5) {
  right: 0;
  top: 50%;
  transform: rotate(180deg);
  animation-delay: .65s;
}
.geer-wrap span:nth-child(6) {
  right: 10%;
  bottom: 10%;
  transform: rotate(225deg);
  animation-delay: .78s;
}
.geer-wrap span:nth-child(7) {
  left: 40%;
  bottom: 0;
  transform: rotate(270deg);
  animation-delay: .91s;
}
.geer-wrap span:nth-child(8) {
  left: 10%;
  bottom: 10%;
  transform: rotate(315deg);
  animation-delay: 1.04s;
}
@keyframes fs-geer-load {
  0% {
    background-color: #3d77e0;
  }
  100% {
    background-color: #ffffff;
  }
}

# 经典压轴 - 长短变化的圆环加载动效

  真的是到处都是这个效果,但是去百度上找了一圈都没找到实现案例。经过自己的折腾,写了两种实现方式,分享给大家。

方案1:利用左右两个半圆挡板按一定规律显示隐藏来展示背景颜色,再加上有效半圆转过面积来实现小于半圆和大于半圆时的不同角度效果

  先看以下案例:

上半程 下半程

材料】一个粉色的底部圆盘,一个粉色的半圆,两个浅绿色的半圆。其中,底部圆盘z-index最小,粉色圆盘夹在两个浅绿色半圆中间。

思路
  借用一下张鑫旭大神的几张分解图,解释的非常到位.

注意,我们只需要转动其中一个半圆,其余的只需要控制显示隐藏即可。

  1. 刚开始转动的时候,隐藏半个挡板



  2. 转动一半时,能看到半个圆了,此时,准备显示刚隐藏的挡板


  1. 将半个最高层浅绿色的挡板隐藏,显示原先被隐藏的挡板,如下


  2. 最终转动到整个圆全部显示,如下


  思路明确了就简单了,我们来看看代码实现:

<div class="wrap cake-wrap">
    <div class="mask-plate">
      <div class="spin-cake"></div>
      <div class="fixed-mask"></div>
      <div class="fixed-cake"></div>
    </div>
</div>
.mask-plate {
    position: absolute;
    width: 5rem;
    height: 5rem;
    border-radius: 50%;
    background: hotpink;
    animation: hide2show 6s linear infinite;
    opacity: 1;
}
.spin-cake {
    position: absolute;
    width: 2.5rem;
    height: 5rem;
    border-radius: 2.5rem 0 0 2.5rem;
    transform-origin: right;
    background: aquamarine;
    animation: spinner 3s linear infinite;
}
.fixed-mask {
    position: absolute;
    width: 2.5rem;
    height: 5rem;
    border-radius: 2.5rem 0 0 2.5rem;
    background: hotpink;
    animation: show2hide 3s linear infinite;
}
.fixed-cake {
    position: absolute;
    left: 50%;
    width: 2.5rem;
    height: 5rem;
    border-radius: 0 2.5rem 2.5rem 0;
    background: aquamarine;
    animation: hide2show 3s linear infinite;
}
@keyframes spinner {
  0% {
    transform: rotate(360deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}
@keyframes show2hide {
  0%, 49.9% {
    opacity: 1;
  }
  50%, 100% {
    opacity: 0;
  }
}
@keyframes hide2show {
  0%, 49.9% {
    opacity: 0;
  }
  50%, 100% {
    opacity: 1;
  }
}

  其实到这里还没结束,该效果你会看到粉色圆转好了之后,立马就从头开始,体验并不好。于是我们还需要再实现一套由粉色圆转出浅绿色圆的。代码一样,不再赘述。

  实现以上饼转效果之后,相信你已经想到怎么实现长短变化的圆环loading效果了。没错,只需要把圆改成圆环,半圆改成半圆环就好可以了。

方案2 利用伪元素::after:before 实现对整个圆环的遮挡效果来实现

很容易看懂两个半圆与底部白色圆环之间的关系,通过控制两个半圆的旋转速度差来实现露出部分圆环的大小。

上代码

<div class="wrap rollelongate-wrap">
  <span></span>
</div>
.rollelongate-wrap span {
  display: block;
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  border: .5rem solid #ffffff;
  animation: fs-rollelongate-parent-load 5s linear infinite;
}
.rollelongate-wrap span:before {
  width: 3rem;
  height: 5.5rem;
  border-radius: 5.5rem 0 0 5.5rem;
  background-color: #c3c3c3;
  position: absolute;
  /*top: -.3rem;*/   /*如果.rollelongate-wrap span的animation不开用这个*/
  top: -.8rem;
  left: -.9rem;
  content: '';
  transform-origin: right center;
  -webkit-transform-origin: right center;
  transform: rotate(20deg);
  animation: fs-rollelongate-load 1.6s ease infinite;
  -webkit-animation: fs-rollelongate-load 1.6s ease infinite;
}
.rollelongate-wrap span:after {
  width: 3rem;
  height: 5.5rem;
  border-radius: 0 5.5rem 5.5rem 0;
  background-color: #c3c3c3;
  position: absolute;
  /*top: -.2rem;*/   /*如果.rollelongate-wrap span的animation不开用这个*/
  top: -.8rem;
  content: '';
  transform-origin: left center;
  -webkit-transform-origin: left center;
  animation: fs-rollelongate-load 1.6s .3s ease infinite;
  -webkit-animation: fs-rollelongate-load 1.6s .3s ease infinite;
}
@keyframes fs-rollelongate-load {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes fs-rollelongate-parent-load {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

# 后语

  编辑上有点粗糙还望大家见谅,没有找到合适的制作gif的软件,只能分解动态图给大家看,如果还有不理解的地方,欢迎来交流。

上一篇下一篇

猜你喜欢

热点阅读