Material Design的Loading动画

作者: im宇 | 来源:发表于2016-10-04 15:36 被阅读1157次

    写在前面:
    这是一篇菜鸟的学习笔记,记录效果实现过程,而没有考虑安全、兼容、性等问题。供新手参考,也希望前辈们指点。

    这篇文章将一步一步记录实现一个Material Design的Loading动画,该效果模仿自Materialize网站的Loading动画,效果如下:

    Materialize网站的效果.gif 我的最终效果.gif

    Loading链接展示

    实现的小思路:

    之前一直在想通过border的方法只能是实现一个完整的圆圈(或缺n*45°的圆圈),但是上面的效果明显是一个可变长度的圆圈的一部分,那么该如何实现呢?后来查看了下Materialize网站Loading部分的css布局。发现原来是另一种思路的实现。Materialize是通过一个小div设置overflow:hidden属性将圆圈的一半给挡住,然后在同个border-left等属性使圆圈只有一半,这样结合transform: rotate()属性选择这一半的圆圈就可以实现非完整圆圈了。而实际上实现上图任意程度的非完整圆圈,需要使用两个div分别各占布局的左右以及两个半圆来实现。具体如何使用,参考详解用CSS3制作圆形滚动进度条动画效果

    第一部分动画(去掉外布局旋转的效果)

    • 先来看看Materialize的效果:
    去掉外布局旋转的效果.gif
    • 我的实现效果:
    动画一.gif
    • 我的实现思路:
      大布局下分为两个div,两个div下又有各自的圆圈。同时设置旋转动画以达到该效果。
    • 实现代码:
    <!DOCTYPE html>
    <html>
    <head>
        <mate charset="utf-8"></mate>
        <title>Material Design Loading Animation</title>
        <style>
            /*外层布局*/
            .circle-layout{
                width: 110px;
                height: 110px;
            }
            /*左div*/
            .layout-left{
                float: left;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*右div*/
            .layout-right{
                float: right;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*左圈*/
            .circle-left{
                position: absolute;
                top: 0;
                left: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-left: 5px solid transparent;
                border-bottom: 5px solid transparent;
                transform: rotate(40deg);
                animation: animation-circle-left 1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*右圈*/
            .circle-right{
                position: absolute;
                top: 0;
                right: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-right: 5px solid transparent;
                border-top: 5px solid transparent;
                transform: rotate(-310deg);
                animation: animation-circle-right 1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*左圈动画*/
            @keyframes animation-circle-left{
                0%{
                    transform: rotate(40deg);
                }
                50%{
                    transform: rotate(-100deg);
                }
                100%{
                    transform: rotate(40deg);
                }
            }
            /*右圈动画*/
            @keyframes animation-circle-right{
                0%{
                    transform: rotate(-310deg);
                }
                50%{
                    transform: rotate(-170deg);
                }
                100%{
                    transform: rotate(-310deg);
                }
            }
        </style>
    </head>
    <body>
        <div class="circle-layout">
            <div class="layout-left">
                <div class="circle-left"></div>
            </div>
            <div class="layout-right">
                <div class="circle-right"></div>
            </div>
        <div>
    </body>
    </html>
    

    第二部分动画(加上外层布局旋转的效果)

    • 先来看看Materialize的效果:
    加上外布局旋转的效果.gif
    • 我的实现效果:
    动画二.gif
    • 我的实现思路:
      仔细看就会发现这个动画是先从一个点往前进方向伸张,然后又从尾部开始往前进方向收缩成一个点。那么如何通过上面“去掉外布局旋转的效果”基本动画得到“加上外布局旋转的效果”动画呢?从名字当中就可以看出来,答案就是加上外布局的旋转。外布局的动画时间是基本动画时间的两倍,总旋转角度为720°,旋转速度大致与“基本动画”相当(本来应该是一致,但注意到“基本动画”的圆圈伸张距离并没有达到360°,而外布局的动画又要在周期之间灰度过度)。
      细心的人会注意到“加上外布局旋转的效果”与“动画二”的效果不大一样:前者的圆圈缺口方向会改变,二后者的方向一直向上。好吧,我承认是我不知道如何做到前者的效果。但看下面“动画三”的效果与Materialize的效果还是比较像的,先这样凑合用着吧!_

    • 代码实现:

    <!DOCTYPE html>
    <html>
    <head>
        <mate charset="utf-8"></mate>
        <title>Material Design Loading Animation</title>
        <style>
            /*外层布局*/
            .circle-layout{
                width: 110px;
                height: 110px;
                animation: animation-circle 4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*左div*/
            .layout-left{
                float: left;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*右div*/
            .layout-right{
                float: right;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*左圈*/
            .circle-left{
                position: absolute;
                top: 0;
                left: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-left: 5px solid transparent;
                border-bottom: 5px solid transparent;
                transform: rotate(40deg);
                animation: animation-circle-left 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*右圈*/
            .circle-right{
                position: absolute;
                top: 0;
                right: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-right: 5px solid transparent;
                border-top: 5px solid transparent;
                transform: rotate(-310deg);
                animation: animation-circle-right 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*左圈动画*/
            @keyframes animation-circle-left{
                0%{
                    transform: rotate(40deg);
                }
                50%{
                    transform: rotate(-100deg);
                }
                100%{
                    transform: rotate(40deg);
                }
            }
            /*右圈动画*/
            @keyframes animation-circle-right{
                0%{
                    transform: rotate(-310deg);
                }
                50%{
                    transform: rotate(-170deg);
                }
                100%{
                    transform: rotate(-310deg);
                }
            }
            /*外层动画*/
            @keyframes animation-circle{
                0%{
                    transform: rotate(0deg);
                }
                25%{
                    transform: rotate(180deg);
                }
                50%{
                    transform: rotate(360deg);
                }
                75%{
                    transform: rotate(540deg);
                }
                100%{
                    transform: rotate(720deg);
                }
            }
            
        </style>
    </head>
    <body>
        <div class="circle-layout">
            <div class="layout-left">
                <div class="circle-left"></div>
            </div>
            <div class="layout-right">
                <div class="circle-right"></div>
            </div>
        <div>
    </body>
    </html>
    

    第三部分动画(在加一个最外层布局)

    • 先来看看Materialize的效果:
    在加最外层布局旋转的效果.gif
    • 我的实现效果:
    动画三.gif
    • 我的实现思路:
      “动画三”只是在“动画二”的基础上加上了一层旋转,以达到圆圈缺口方向的变化仅此而已。至于圆圈缺口的变化,读者可自行修改animation-wrap动画以及animation-circle动画的时间以调整效果,但是必须保证animation-circle的动画时间一定是animation-circle-left/right的两倍。

    • 实现代码:

    <!DOCTYPE html>
    <html>
    <head>
        <mate charset="utf-8"></mate>
        <title>Material Design Loading Animation</title>
        <style>
        body{
            margin: 100px 200px;
        }
            /*最外层布局*/
            .wrap{
                width: 110px;
                height: 110px;
                animation: animation-wrap 2.5s linear infinite;
            }
            /*外层布局*/
            .circle-layout{
                width: 110px;
                height: 110px;
                animation: animation-circle 3s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*左div*/
            .layout-left{
                float: left;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*右div*/
            .layout-right{
                float: right;
                width: 50%;
                height: 100%;
                overflow: hidden;
                position: relative;
            }
            /*左圈*/
            .circle-left{
                position: absolute;
                top: 0;
                left: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-left: 5px solid transparent;
                border-bottom: 5px solid transparent;
                transform: rotate(40deg);
                animation: animation-circle-left 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*右圈*/
            .circle-right{
                position: absolute;
                top: 0;
                right: 0;
                width: 100px;
                height: 100px;
                border: 5px solid #F88E8B;
                border-radius: 50%;
                border-right: 5px solid transparent;
                border-top: 5px solid transparent;
                transform: rotate(-310deg);
                animation: animation-circle-right 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
            }
            /*左圈动画*/
            @keyframes animation-circle-left{
                0%{
                    transform: rotate(40deg);
                }
                50%{
                    transform: rotate(-100deg);
                }
                100%{
                    transform: rotate(40deg);
                }
            }
            /*右圈动画*/
            @keyframes animation-circle-right{
                0%{
                    transform: rotate(-310deg);
                }
                50%{
                    transform: rotate(-170deg);
                }
                100%{
                    transform: rotate(-310deg);
                }
            }
            /*外层动画*/
            @keyframes animation-circle{
                0%{
                    transform: rotate(0deg);
                }
                25%{
                    transform: rotate(180deg);
                }
                50%{
                    transform: rotate(360deg);
                }
                75%{
                    transform: rotate(540deg);
                }
                100%{
                    transform: rotate(720deg);
                }
            }
            /*最外层动画*/
            @keyframes animation-wrap{
                0%{
                    transform: rotate(0deg);
                }
                100%{
                    transform: rotate(360deg);
                }
            }
            
        </style>
    </head>
    <body>
        <div class="wrap">
            <div class="circle-layout">
                <div class="layout-left">
                    <div class="circle-left"></div>
                </div>
                <div class="layout-right">
                    <div class="circle-right"></div>
                </div>
            <div>
        </div>
    </body>
    </html>
    

    后续内容

    将该效果封装成可复用且方便使用的控件,打算使用js动态生成众多的布局减少html中的代码量。


    更新,2016.10.6
    完成后续内容,同时增加可设置大小颜色功能


    最终效果如下:

    是不是和Materialize网站的很接近了。_

    最终效果.gif

    代码如下:

    <!DOCTYPE html>
    <html>
    <head>
        <mate charset="utf-8"></mate>
        <title>Material Design Loading Animation</title>
        <link rel="stylesheet" type="text/css" href="loading.css"></link>
        <script type="text/javascript" src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
        <script>
            $(document).ready(function(){
                function LoadingClass(){
                    this.wrap = jQuery(".mmd-loading-wrap");
                    this.run = function(){
                        this.wrap.each(function(i){
                        
                            //计算圆圈的宽度
                            var bw = Math.round($(this).width()/15);
                            var w = $(this).width() - 2 * bw;
                            //通过自定义属性得到圆圈的颜色
                            var circleColor = $(this).attr("circleColor");
                            
                            //动态生成圆圈。即将上一个版本中html的代码搬移到js中,减低html代码使用量
                            var div = "<div class='mmd-loading-circle-layout'>"
                                  +"<div class='mmd-loading-layout-left'>"
                                    +"<div class='mmd-loading-circle-left'"
                                        +"style='width:"+w+"px;height:"+w+"px;border-width:"+bw+"px;border-color:"+circleColor+";"
                                            +"border-left:"+bw+"px solid transparent;"+"border-bottom:"+bw+"px solid transparent;'"+"></div>"
                                  +"</div>"
                                  +"<div class='mmd-loading-layout-right'>"
                                    +"<div class='mmd-loading-circle-right'"
                                        +"style='width:"+w+"px;height:"+w+"px;border-width:"+bw+"px;border-color:"+circleColor+";"
                                            +"border-right:"+bw+"px solid transparent;"+"border-top:"+bw+"px solid transparent;'"+"></div>"
                                  +"</div>"
                              +"</div>";
                            $(this).append(div);
                        });
                    }
                }
                //自动运行
                (function(){
                    var loading = new LoadingClass();
                    loading.run();
                })();
            });
        </script>
    </head>
    <body>
        <!-- 需要设置circleColor -->
        <div class="mmd-loading-wrap" style="width:60px;height:60px;position:absolute;left:300px;top:100px;" circleColor="#F88E8B"></div>
        <div class="mmd-loading-wrap" style="width:40px;height:40px;position:absolute;left:500px;top:100px;" circleColor="#DC4C40"></div>
        <div class="mmd-loading-wrap" style="width:30px;height:30px;position:absolute;left:700px;top:100px;" circleColor="#26A668"></div>
    </body>
    </html>
    

    附上源码:

    Loading示例代码

    相关文章

      网友评论

        本文标题:Material Design的Loading动画

        本文链接:https://www.haomeiwen.com/subject/iowjyttx.html