likes
comments
collection
share

CSS animation 实现 4 圆点跳动 loading

作者站长头像
站长
· 阅读数 18

开篇

CSS3 animation 动画可以实现很多功能,比如项目中常用到的 loading 效果。

最近项目中涉及到一个 loading 交互:“四个小圆点依次跳动”。最初采用 UI 涉及的 gif 动图来呈现加载效果,但由于动图的体积太大,最终改用 CSS3 animation 来实现。最终效果展示如下:

CSS animation 实现 4 圆点跳动 loading

分析

从效果图中可以看出,圆点跳动的交互有两个:上移 和 放大,在 CSS3 中 transform translateY/scale 可以轻松实现。

接下来为了让其动起来,需要通过定义 animation 动画来完成。

我们先来回顾 animation 常用属性:

  1. animation-name && @keyframes

@keyframes 用于定义一个动画,animation-name 是设置当前元素要使用的动画。在定义动画时,from/to 或者 百分比进度 都可以定义动画每个阶段呈现的效果:

@keyframes example {  
  from {background-color: red;}  
  to {background-color: yellow;}  
}

// or

@keyframes example {  
  0%   {background-color: red;}  
  25%  {background-color: yellow;}  
  50%  {background-color: blue;}  
  100% {background-color: green;}  
}

div{
  animation-name: example;  
  animation-duration4s;
}
  1. animation-duration

指定动画需要多少秒或毫秒完成。

animation-duration4s;
  1. animation-timing-function

指定动画将如何完成一个周期,可选值有:

  • linear,动画从头到尾的速度是相同的;
  • ease,默认。动画以低速开始,然后加快,在结束前变慢。
  • ease-in,动画以低速开始。
  • ease-out,动画以低速结束。
  • ease-in-out,动画以低速开始和结束。
animation-timing-function:linear;
  1. animation-delay

用于延迟动画的执行时间。

animation-delay2s;
  1. animation-iteration-count

定义动画的播放次数。可以设定数字来确认播放次数,当设置 infinite 时表示无限次播放。

animation-iteration-count: infinite;
  1. animation-direction

指定是否应该轮流反向播放动画。可选值有:

  • normal,默认值。动画按正常播放。
  • reverse,动画反向播放。
  • alternate,动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放。
  • alternate-reverse,动画在奇数次(1、3、5...)反向播放,在偶数次(2、4、6...)正向播放。

要实现 loading 跳动动画,使用到的动画属性如下:

  • animation-name,指定动画名称
  • animation-duration,指定动画完成一轮所用的时间
  • animation-delay,指定动画延迟执行时间
  • animation-iteration-count,指定动画播放次数,我们使用 infinite 无限次播放

下面我们来看看完整代码实现:

完整代码

  1. 首先是 DOM 节点,我们只需一个容器 和 四个小圆点元素即可:
<div class="box">
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>
  1. css 样式,借助 animation 来实现,
  • 每个圆点的动画执行时机不同,这里使用 animation-delay 做延迟执行:
  • 由于产品设计上第四个圆点的跳动交互与前三个不同,所以单独设定 loading-beat-last
<style>
  *{
    padding: 0;
    bottom: 0;
  }
  
  .box{
    width: 100px;
    height: 50px;
    margin: 100px auto;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  
  span{
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 5px;
    animation-name: loading-beat;
    /* 动画完成一个周期所需要的时间 */
    animation-duration: 1.2s;
    /* 定义动画从何时开始(延迟) */
    animation-delay: 0s;
    /* 动画播放次数(无限) */
    animation-iteration-count: infinite;
  }
  
  span:nth-child(1){
    background: #E6804A;
  }
  span:nth-child(2){
    background: #FFD14E;
    animation-delay: .2s;
  }
  span:nth-child(3){
    background: #54BFFF;
    animation-delay: .4s;
  }
  span:nth-child(4){
    background: #59D8AB;
    animation-delay: .6s;
    animation-name: loading-beat-last;
  }

  @keyframes loading-beat {
    0%{
      transform: translateY(0) scale(1);
    }
    25% {
      transform: translateY(-8px) scale(1.5);
    }
    50%, 75%, 100% {
      transform: translateY(0px) scale(1);
    }
  }
  
  @keyframes loading-beat-last {
    0%{
      transform: translateY(0) scale(1);
    }
    25%, 50% {
      transform: translateY(-8px) scale(1.5);
    }
    60% {
      transform: translateY(0px) scale(1);
    }
  }
</style>