zoukankan      html  css  js  c++  java
  • 深入理解CSS动画animation

    前面的话

      transition过渡是通过初始和结束两个状态之间的平滑过渡实现简单动画的;而animation则是通过关键帧@keyframes来实现更为复杂的动画效果。本文将介绍关于animation动画的相关知识

    定义

      和transition类似,animation也是一个复合属性,包括animation-name、animation-duration、animation-timing-function、animation-delay、animation-iteration-count、animation-direction、animation-play-state、animation-fill-mode共8个子属性

      [注意]IE9-不支持;safari4-8、IOS3.2-8.4、android2.1-4.4.4需要添加-webkit-前缀

    animation-name: 动画名称(默认值为none)
    animation-duration: 持续时间(默认值为0)
    animation-timing-function: 时间函数(默认值为ease)
    animation-delay: 延迟时间(默认值为0)
    animation-iteration-count: 循环次数(默认值为1)
    animation-direction: 动画方向(默认值为normal)
    animation-play-state: 播放状态(默认值为running)
    animation-fill-mode: 填充模式(默认值为none)
    div{
        width: 300px;
        height: 100px;
        background-color: pink;
        animation-name: test;
        animation-duration: 3s;
        animation-timing-function: ease;
        animation-delay: 0s;
        animation-iteration-count: infinite;
        animation-direction: normal;
        animation-play-state: running;
        animation-fill-mode: none;
    }
    /* 关于keyframes关键帧的内容稍后介绍     */
    @keyframes test{
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
    }

    关键帧

      animation制作动画效果需要两步,首先用关键帧声明动画,再用animation调用动画

      关键帧的语法是以@keyframes开头,后面紧跟着动画名称animation-name。from等同于0%,to等同于100%。百分比跟随的花括号里面的代码,代表此时对应的样式

    @keyframes animation-name{
        from | 0%{}
        n%{}
        to | 100%{}
    }

    【1】百分比顺序不一定非要从0%到100%排列,最终浏览器会自动按照0%-100%的顺序进行解析

      [注意]0%不可以省略百分号

    @keyframes test{
        100%{background-color: black;}
        60%{background-color: lightgray;}
        30%{background-color: lightgreen;}
        0%{background-color: lightblue;}
    }
    div{
         300px;
        height: 100px;
        background-color: pink;
        animation-name: test;
        animation-duration: 3s;
        animation-iteration-count: infinite;
    }

    【2】如果存在负百分数或高于100%的百分数,则该关键帧将被忽略

    /* -20%和120%对应的代码无效*/
    @keyframes test{
        -20%{background-color: red;}
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
        120%{background-color: yellow;}
    }

    【3】如果0%或100%不指定关键帧,将使用该元素默认的属性值

    /* 0%和100%对应的颜色是默认值pink*/
    @keyframes test{
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
    }

    【4】若存在多个@keyframes,浏览器只识别最后一个@keyframes里面的值 

    /* 后面覆盖前面 */
    @keyframes test{
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
    }
    @keyframes test{
        0%{background-color: blue;}
        30%{background-color: green;}
        60%{background-color: gray;}
        100%{background-color: black;}
    }

    【5】空的keyframes规则是有效的,它们会覆盖前面有效的关键帧规则

    /* 后面覆盖前面 */
    @keyframes test{
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
    }
    @keyframes test{
    }

    动画属性

    动画名称

    animation-name

      值: none | <single-animation-name> [, <single-animation-name> ]*

      初始值: none

      应用于: 所有元素

      继承性: 无

    <single-animation-name>: none | 自定义动画名称

    【1】如果多个动画试图修改相同的属性,那么动画列表的后面覆盖前面

    /* animation-name的顺序是test1,test2,且它们修改的是同样的属性,后面覆盖前面,所以test2有效,test1无效 */
    div{
         300px;
        height: 100px;
        background-color: pink;
        animation-name: test1,test2;
        animation-duration: 3s;
        animation-iteration-count: infinite;
    }
    @keyframes test2{
        0%{background-color: blue;}
        30%{background-color: green;}
        60%{background-color: gray;}
        100%{background-color: black;}
    }
    @keyframes test1{
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
    }

    【2】如果动画的其他7个子属性和动画名称的长度不同,动画名称列表的长度决定最终的长度,多余的值无余,缺少的值按照顺序进行重复

    div{
         300px;
        height: 100px;
        position: relative;
        background-color: pink;
        animation-name: test1,test2,test3;
        animation-duration: 3s,1s;
        animation-iteration-count: infinite;
    }
    @keyframes test1{
        0%{background-color: lightblue;}
        30%{background-color: lightgreen;}
        60%{background-color: lightgray;}
        100%{background-color: black;}
    }
    @keyframes test2{
        0%{font-size: 20px;}
        30%{font-size: 30px;}
        60%{font-size: 40px;}
        100%{font-size: 50px;}
    }
    @keyframes test3{
        0%{left: 0px;}
        30%{left: 30px;}
        60%{left: 40px;}
        100%{left: 50px;}
    }
    <div>测试文字</div>    

    持续时间

      持续时间指完成动画的时间

    animation-duration

      值: <time> [, <time>]*

      初始值: 0s

      应用于: 所有元素

      继承性: 无

    animation-duration: <time>[,<time>]*

      0s意味着动画没有时间,持续时间不能为负值

    animation-name: test1,test2;
    /*test1的持续时间设置为负值,将使得整个动画持续时间都失效,因此test2也将没有动画效果 */
    animation-duration: -1s,1s;

    时间函数

    animation-timing-function

      值: <single-timing-function> [, <single-timing-function>]*

      初始值: ease

      应用于: 所有元素

      继承性: 无

      animation的时间函数类似于transition的时间函数。时间函数可以应用于整个动画中,也可以应用于关键帧的某两个百分比之间

    div{
         300px;
        height: 100px;
        position: relative;
        background-color: pink;
        animation-name: test;
        animation-duration: 5s;
        animation-iteration-count: infinite;
    }
    
    @keyframes test{
        0%{left: 0px;animation-timing-function: ease;}
        20%{left: 50px;animation-timing-function: linear;}
        40%{left: 100px;animation-timing-function: ease-in;}
        60%{left: 150px;animation-timing-function: ease-out;}
        80%{left: 200px;animation-timing-function: step-start;}
        100%{left: 250px;animation-timing-function: step-end;}
    }

    循环次数

    animation-iteration-count

      值: infinite | <number>[,infinite | <number>]*

      初始值: 1

      应用于: 所有元素

      继承性: 无

      默认为1,可以是整数也可以小数,但不能是0和负数。如果为infinite则表示无限次动画

    动画方向

      动画方向用来定义是否动画需要反向播放

    animation-direction

      值: <single-animation-direction>[,<single-animation-direction> ]*

      初始值: normal

      应用于: 所有元素

      继承性: 无

    <single-animation-direction> = normal | reverse | alternate | alternate-reverse
    normal: 正向播放
    reverse: 反向播放
    alternate: 若动画只播放一次,则和正向播放一样。若播放两次以上,偶数次效果为反向播放
    alternate-reverse: 若动画只播放一次,则和反向播放一样。若播放两次以上,偶数次效果为正向播放

      [注意]safari浏览器不支持reverse属性和alternate-reverse属性

    动画状态

    animation-play-state

      值:running | paused[,running | paused]*

      初始值: running

      应用于: 所有元素

      继承性: 无

      running表示播放中,paused表示动画暂停

    延迟时间

      定义延迟多少时间后动画开始播放

    animation-delay

      值: <single-animation-delay>[,<single-animation-delay> ]*

      初始值: 0s

      应用于: 所有元素

      继承性: 无

    <single-animation-delay>= <time>[,<time>]*

      [注意]该延迟时间是指整个动画的延迟时间,而不是每个循环的延迟时间,只在动画开始时进行一次时间延迟

      如果该值是负值,则表示动画的起始时间从0s变为延迟时间的绝对值

    填充模式

      定义动画开始帧之前和结束帧之后的动作

      [注意]android2.1-3不支持animation-fill-mode

    animation-fill-mode

      值: <single-animation-fill-mode>[,<single-animation-fill-mode> ]*

      初始值: none

      应用于: 所有元素

      继承性: 无

    <single-animation-fill-mode> = none | forwards | backwards | both
    none: 动画结束后,元素移动到初始状态
        [注意]初始状态并不是指0%的元素状态,而是元素本身属性值
    forwards: 元素停在动画结束时的位置
        [注意]动画结束时的位置并不一定是100%定义的位置,因为动画有可能反向运动,也有可能动画的次数是小数
    backwards:在animation-delay的时间内,元素立刻移动到动画开始时的位置。若元素无animation-delay时,与none的效果相同
        [注意]动画开始时的位置也不一定是0%定义的位置,因为动画有可能反向运动。
    both: 同时具有forwards和backwards的效果

      [注意]当持续时间animation-duration为0s时,animation-fill-mode依然适用,当animation-fill-mode的值为backwards时,动画填充在任何animation-delay的阶段。当animation-fill-mode的值为forwards时,动画将保留在100%的关键帧上

    多值

    animation

      值: <single-animation>[,<single-animation> ]*

      初始值: 无

      应用于: 所有元素

      继承性: 无

    <single-animation> = <single-animation-name> || <single-animation-duration> || <single-animation-timing-function> || <single-animation-delay> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state>

      [注意]持续时间在前,延迟时间在后,若只存在一个时间,则是持续时间

    div{
         300px;
        height: 100px;
        background-color: pink;
        animation: 1s test1,infinite test2 2s 1s;
    }
    @keyframes test1{
        30%{background-color: red;}
        60%{background-color: blue;}
        100%{background-color: green;}
    }
    @keyframes test2{
        100%{color: white;}
    }

    API

      animation涉及到的事件有animationstart、animationend、animationiteration三个。这三个事件的bubbles都是yes,cancelable都是no

      [注意]对于safari浏览器,animation的事件为webkitAnimationStart、webkitAnimationEnd、webkitAnimationIteration

      [注意]动画事件只支持DOM2级事件处理程序的写法

    animationstart

      发生在动画开始时

      【1】如果存在delay,且delay为正值,则元素等待延迟完毕后,再触发该事件

      【2】如果delay为负值,则元素先将初始值变为delay的绝对值时,再触发该事件

        oSb.addEventListener('animationstart',function(){
            this.innerHTML = '动画开始';
            this.style.background = 'lightgreen';
        },false);

    animationend

      发生在动画结束时

    test.addEventListener('animationend',function(){
        this.style.background="lightgreen";
        this.innerHTML = '动画结束';
    },false);

    animationiteration

      发生在动画的一次循环结束时,只有当iteration-count循环次数大于1时,触发该事件

    var i = 0;
    oSb.addEventListener('animationiteration',function(){
        i++;
        this.innerHTML = i;
    },false);

    【补充】

      只有改变animation-name时,才会使animation动画效果重新触发

    oSb.style.animationName = 'none';
    setTimeout(function(){
        oSb.style.animationName = 'test';
    },100);

    属性

      这三个事件的事件对象,都有animationName和elapsedTime属性这两个私有属性

    animationName属性:返回产生过渡效果的CSS属性名
    elapsedTime属性:动画已经运行的秒数

      [注意]对于animationstart事件,elapsedTime属性等于0,除非animation-delay属性等于负值

    <style>
    #test{height:100px;width:300px;background-color:lightblue;animation:anim 2s 3;}
    @keyframes anim{
        0%{height: 100px;}
        50%{height: 50px;}
        100%{height: 0;}
    }
    </style>
    
    <button id='reset'>还原</button>
    <div id="test"></div>
    <script>
    reset.onclick = function(){
        history.go();
    }
    test.addEventListener("animationstart", listener, false);
    test.addEventListener("animationend", listener, false);
    test.addEventListener("animationiteration", listener, false);
    function listener(e){
        e = e || event;
        var li = document.createElement("li");
        switch(e.type) {
        case "animationstart":
          li.innerHTML = "Started: elapsed time is " + e.elapsedTime;
          break;
        case "animationend":
          li.innerHTML = "Ended: elapsed time is " + e.elapsedTime;
          break;
        case "animationiteration":
          li.innerHTML = "New loop started at time " + e.elapsedTime;
          break;
        }
        test.appendChild(li);
    }
    </script>

  • 相关阅读:
    修改VNC的分辨率
    How to use WinSCP with public key authentication
    CentOS-7-x86_64-DVD-1511.iso
    6.828
    Tampermonkey版Vimium
    servlet+jsp完成简单登录
    Servlet知识点小结
    HTTP基础知识点小结
    LeetCode 371两数之和
    LeetCode53 最大子序列问题
  • 原文地址:https://www.cnblogs.com/xiaohuochai/p/5391663.html
Copyright © 2011-2022 走看看