CSS animation 属性

  • 定义和用法 animation 属性是一个简写属性,用于设置六个动画属性:

    • animation-name
    • animation-duration
    • animation-timing-function
    • animation-delay
    • animation-iteration-count
    • animation-direction
    • 注释:请始终规定 animation-duration 属性,否则时长为 0,就不会播放动画了 !!!!!
  • CSS 语法

animation: name duration timing-function delay iteration-count direction;

描述
animation-name规定需要绑定到选择器的 keyframe 名称。
animation-duration规定完成动画所花费的时间,以秒或毫秒计。
animation-timing-function规定动画的速度曲线。
animation-delay规定在动画开始之前的延迟。
animation-iteration-count规定动画应该播放的次数。
animation-direction规定是否应该轮流反向播放动画。
animation-fill-mode规定动画在执行时间之外应用的值。
animation-play-state规定动画是正在运行还是暂停。

基本了解

css中实现动画有两种方式:transition过渡动画、 animation自定义动画。

animation动画的使用,若要了解transition过渡动画请前往transition过渡动画open in new window

简单了解下animation的一些语法和使用过程,后面会详细解说:

  1. 通过@keyframes自定义关键帧动画并为动画命名,可以在其中对每一帧进行设置。

  2. 使用自定义动画的元素,需要通过

    animation
    

    相关属性进行配置

    • animation-name
    • animation-duration
    • animation-timing-function
    • animation-delay
    • animation-iteration-count
    • animation-direction
    • animation-fill-mode
    • animation-play-state

我们还可在JavaScript中,通过驼峰式命名来访问/设置animation相关属性。

@keyframes

keyframes(关键帧),在css样式表中可以通过@keyframes来设置关键帧动画,并指定动画名称供使用者锁定。

其语法如下:

我们可以通过百分比来设置具体帧数的样式。

@keyframes animateName{
    0%   { width:50px; height:50px; }	
    50%  { width:100px; height:100px; }	
    100% { width:50px; height:50px; }
}

0%100%代表首尾帧,也可分别使用fromto替代。下面代码与上述代码效果相同

@keyframes animateName{
    from { width:50px; height:50px; }	
    50%  { width:100px; height:100px; }	
    to	 { width:50px; height:50px; }
}

需要注意的是: 若自定义动画未定义首尾帧,则首尾帧将会应用使用者的原有样式

现在动画定义完毕,使用者需要配置animation相关属性对动画进行配置。

animation-name

若某个元素想要使用对应名称的动画,需要配置animation-name: animateName属性进行锁定。

 <style>
  .box {
    width: 50px;
    height: 50px;
    background-color: pink;
    animation-name: test;
    animation-duration: 1s;
    animation-iteration-count: infinite;
  }
  @keyframes test {
    50% {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background-color: skyblue;
    }
  }
</style>
<body>
  <div class="box"></div>
</body>

这里为了让动画更加明显,使用了animation-durationanimation-iteration-count,这里简单介绍一下:

  • animation-duration 用于定义动画持续时间,默认0s
  • animation-iteration-count 用于定义动画迭代次数,也就是执行次数,默认为1

animation-duration

animation-duration顾名思义,用于设置动画持续时间.

​ 需要注意的是:默认值为0s,也就是说,若不配置animation-duration则默认请况下是没有动画效果的,即便使用animation-name锁定了动画名称,由于动画持续时间为0s,所以没有效果。

animation-timing-function:

animation-timing-function用于定义时间函数,通过这个选项,可配置动画随时间的运动速率和轨迹。

描述
linear动画从头到尾的速度是相同的。
ease(缓解)默认值:动画以低速开始,然后加快,在结束前变慢。
ease-in动画以低速开始。
ease-out动画以低速结束。
ease-in-out动画以低速开始和结束。
cubic-bezier(n,n,n,n)贝塞尔曲线(自定义数值),可到相关网站open in new window可视化设置。
 <style>
  * {
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
  }
  body {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    background-color: #34495e;
  }
  ul {
    display: flex;
    flex-direction: row;
    justify-content: center;
    list-style: none;
    display: flex;
  }
  ul > li {
    width: 40%;
    margin: 0px 40px;
    position: relative;
  }
  ul > li > .fa {
    font-size: 4em;
    color: white;
    opacity: 0.8;
    animation: test 2s infinite;
  }
  @keyframes test {
    to {
      transform: translateY(86vh);
    }
  }
  ul > li:nth-of-type(1) > .fa {
    animation-timing-function: linear;
  }
  ul > li:nth-of-type(2) > .fa {
    animation-timing-function: ease;
  }
  ul > li:nth-of-type(3) > .fa {
    animation-timing-function: ease-in;
  }
  ul > li:nth-of-type(4) > .fa {
    animation-timing-function: ease-out;
  }
  ul > li:nth-of-type(5) > .fa {
    animation-timing-function: ease-in-out;
  }
  ul > li:nth-of-type(6) > .fa {
    animation-timing-function: cubic-bezier(0.29, 1.69, 0.39, -0.05);
  }
  li > span {
    position: absolute;
    color: #f1c40f;
  }
  strong {
    color: #e67e22;
    margin: 10px;
  }
</style>
<body>
  <strong>animatin-timing-function:</strong>
  <ul>
    <li>
      <span>linear<br />线性</span>
      <div class="fa">👇</div>
    </li>
    <li>
      <span>ease<br />默认。动画以低速开始,然后加快,在结束前变慢。</span>
      <div class="fa">👇</div>
    </li>
    <li>
      <span>ease-in<br />以低速开始</span>
      <div class="fa">👇</div>
    </li>
    <li>
      <span>ease-out<br />以低速结束</span>
      <div class="fa">👇</div>
    </li>
    <li>
      <span>ease-in-out<br />以低速开始和结束</span>
      <div class="fa">👇</div>
    </li>
    <li>
      <span>cubic-bezier()<br />贝塞尔曲线(自定义数值)</span>
      <div class="fa">👇</div>
    </li>
  </ul>
</body>

animation-delay

animation-delay`用于设置动画延迟时间,单位为`s

下例动画将于2s后执行

 .box {
  width: 50px;
  height: 50px;
  background-color: pink;
  animation-name: test;
  animation-duration: 1s;
  animation-delay: 2s;
}
@keyframes test {
  50% {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-color: skyblue;
  }
}

当同时使用多个动画时,这个属性使用频率非常高,可依次定义每个动画的延迟执行时间,区分开每个动画。

当然其实也可分别设置每个动画的其它animation族属性,后面会详细介绍多动画累加。

animation-iteration-count:

animation-iteration-count用于设置动画执行的次数,默认值为1只执行一次。

其值可分为两种:

  • 具体number数值
  • infinite:执行无限次

animation-direction

animation-direction用于设置动画执行方向,具体来说可设置为以下值:

描述
normal默认值。动画按正常播放。
reverse动画反向播放。
alternate(交替的)动画正向交替执行(正向->反向)Loop。
alternate-reverse动画反向交替执行(反向->正向)Loop。
inherit从父元素继承该属性。

效果展示:

 <style>
  * {
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
  }
  body {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: #34495e;
    justify-content: center;
    align-items: center;
  }
  ul {
    display: flex;
    flex-direction: row;
    list-style: none;
    width: 300px;
    height: 300px;
    justify-content: center;
    align-items: center;
  }
  ul > li {
    margin: 0px 40px;
    /* border: 2px solid #ddd; */
    display: flex;
    flex-direction: column;
    color: #e74c3c;
    justify-content: center;
    align-items: center;
  }
  ul > li > .fa {
    animation: test 1.3s infinite;
    font-size: 7em;
  }
  ul li:nth-of-type(1) > .fa {
    animation-direction: normal;
  }
  ul li:nth-of-type(2) > .fa {
    animation-direction: reverse;
  }
  ul li:nth-of-type(3) > .fa {
    animation-direction: normal;
  }
  ul li:nth-of-type(4) > .fa {
    animation-direction: reverse;
  }
  @keyframes test {
    100% {
      transform: scale(1.7);
    }
  }
  h1 {
    color: white;
    opacity: 0.8;
  }
  li > span {
    font-size: 24px;
    margin: auto;
    margin-top: 30px;
  }
  body ul:nth-of-type(2) li:nth-of-type(1) > .fa {
    animation-direction: alternate;
  }
  body ul:nth-of-type(2) li:nth-of-type(2) > .fa {
    animation-direction: alternate-reverse;
  }
  strong {
    font-size: 20px;
    color: white;
    opacity: 0.76;
  }
</style>
<body>
  <h1>animation-direction:</h1>
  <ul>
    <li>
      <div class="fa">❤</div>
      <span>normal</span>
      <p>默认值/正向</p>
    </li>
    <li>
      <div class="fa">❤</div>
      <span>reverse</span>
      <p>反向进行动画</p>
    </li>
  </ul>
  <strong
    >可以利用默认值normal和reverse,交叉动画的效果,<br />也可以正反向反复交替如下。</strong
  >
  <ul>
    <li>
      <div class="fa">❤</div>
      <span>alternate</span>
      <p>反复交替(正向)</p>
    </li>
    <li>
      <div class="fa">❤</div>
      <span>alternate-reverse</span>
      <p>反复交替(反向)</p>
    </li>
  </ul>
</body>

animation-fill-mode

animation-fill-mode用于设置动画的填充模式,主要应用的属性值为:

描述
none默认值。动画在动画执行前后,不会应用任何样式到目标元素。
forwards在动画结束后(由 animation-iteration-count 决定),目标元素将保持应用最后帧动画。
backwards在动画结束后(由 animation-iteration-count 决定),目标元素将保持应用起始帧动画。

案例测试:

下例代码,在动画执行结束后,将会一直应用最后帧的样式。

 .box {
  width: 50px;
  height: 50px;
  background-color: pink;
  animation-name: test;
  animation-delay: 2s;
  animation-duration: 1s;
  animation-fill-mode: forwards;
  /* animation-iteration-count: infinite; */
}
@keyframes test {
  100% {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-color: skyblue;
  }
}

注意:上述代码若添加animation-iteration-count: infinite,由于动画次数无限执行,不会结束,也就不会应用最后帧样式

animation-play-state

可设置动画的执行状态,通常通过JavaScript动态控制。

  • 默认值为:running
  • 设为paused(暂停),动画将停止执行。

下面动画将不会执行

 .box {
  width: 50px;
  height: 50px;
  background-color: pink;
  animation-name: test;
  animation-delay: 2s;
  animation-duration: 1s;
  animation-play-state: paused; //值为paused将不会执行
}
@keyframes test {
  50% {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-color: skyblue;
  }
}

通过JavaScript动态控制:

 <style>
  .box {
    width: 50px;
    height: 50px;
    background-color: pink;
    animation-name: test;
    animation-duration: 1s;
    animation-iteration-count: infinite;
  }
  @keyframes test {
    50% {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background-color: skyblue;
    }
  }
</style>
<body>
  <div class="box"></div>
  <button onclick="operation('running')">开始</button>
  <button onclick="operation('paused')">停止</button>
  <script>
    function operation(mode) {
      document.querySelector("div").style.animationPlayState = mode;
    }
  </script>
</body>

多动画累加

若元素应用多个动画,我们可以分别控制各个动画的一些属性,来达到区分各个动画的效果。

下面示例,给animation族属性分别设置多个值,来对不同的动画做不同的配置。

animation族属性设置多个值时,各个值之间使用,隔开。

案例:

  1. 首先使用animation-name来锁定使用的各个动画
  2. 之后使用其它的animation族属性,分别约束对应动画,且设置顺序与animation-name使用动画的顺序保持一致。
 <style>
  * {
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
  }
  body {
    background-color: #353b48;
  }
  main {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
    background-color: #487eb0;
    animation-name: bgcolor, bodera, rotat;
    animation-duration: 2s, 2s, 3s;
    animation-iteration-count: 2, 2, 1;
    animation-direction: reverse, normal, normal;
    animation-fill-mode: forwards, forwards, forwards;
  }
  main::after {
    content: "阿顺特烦恼";
    color: white;
    animation: opcity 2s;
    opacity: 0;
    font-size: 1.5em;
    animation-fill-mode: forwards;
    animation-delay: 4s;
  }
  @keyframes opcity {
    25% {
      opacity: 0.2;
    }
    50% {
      opacity: 0.6;
    }
    100% {
      opacity: 0.8;
    }
  }
  @keyframes bgcolor {
    25% {
      background-color: #fbc531;
    }
    50% {
      background-color: #8c7ae6;
    }
    75% {
      background-color: #f5f6fa;
    }
    100% {
      background-color: #e84118;
    }
  }
  @keyframes bodera {
    25% {
      border-radius: 10%;
    }
    50% {
      border-radius: 25%;
    }
    75% {
      border-radius: 38%;
    }
    100% {
      border-radius: 50%;
    }
  }
  @keyframes rotat {
    25% {
      transform: rotate(30deg);
    }
    50% {
      transform: rotate(60deg);
    }
    75% {
      transform: rotate(120deg);
    }
    100% {
      transform: rotate(360deg);
    }
  }
</style>
<body>
  <main></main>
</body>

关键代码解析:

  main {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
    background-color: #487eb0;
    animation-name: bgcolor, bodera, rotat;
    animation-duration: 2s, 2s, 3s;
    animation-iteration-count: 2, 2, 1;
    animation-direction: reverse, normal, normal;
    animation-fill-mode: forwards, forwards, forwards;
  }
  main::after {
    content: "阿顺特烦恼";
    color: white;
    animation: opcity 2s;
    opacity: 0;
    font-size: 1.5em;
    animation-fill-mode: forwards;
    animation-delay: 4s;
  }
  1. 这里为了让文字在其他动画都执行完毕后再显示,为文字动画设置了animation-delay延迟执行,但我们要确定之前动画结束的时间,怎么计算呢?

  2. 我们知道,当应用多个动画时,它们也都是并发执行的,所以我们只要知道执行时间最长的那个动画即可。

 animation-duration: 2s, 2s, 3s;
animation-iteration-count: 2, 2, 1;
  • 执行次数×单次执行时间=动画总时间。因此最大时间=max(2×2 ,2×2, 3×1)=4s
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.min.js"></script>
</head>
<style>
    .app {
        width: 600px;
        height: 600px;
        border: 1px solid black;
        background-color: #88af7c;
        animation-name: lusifer;
        animation-duration: 2s;

        display: flex;
        flex-direction: column;
    }


    @keyframes lusifer {
        0% {
            width: 50px;
            height: 50px;
        }

        50% {
            width: 100px;
            height: 100px;
            border-radius: 50%;
            background-color: skyblue;
        }

        100% {
            width: 600px;
            height: 600px;
        }
    }

    .cad {
        flex: 1;
        border: 1px solid black;
    }


    /* 显示或关闭动画* /
        .open {
        animation: slideContentUp 0.3s linear both;
    }
 
    .close {
        animation: slideContentDown 0.3s linear both;
    }
 
    /* 动态设置高度 */
    /* @keyframes slideContentUp {
        from {
            height: 0;
        }
 
        to {
            height: 80vh;
        }
    }
 
    @keyframes slideContentDown {
        from {
            height: 80vh;
        }
 
        to {
            height: 0;
        }
    }
*/

    /* 显示或关闭动画*/
    .open {
        animation: left 2s ease-in both;
    }

    .close {
        animation: right 2s ease-in both;
    }

    @keyframes left {
        from {
            width: 50px;
            /*最小的宽度,隐藏就写0,我这边图标静止需要一个宽度*/
        }

        to {
            width: 250px;
            /*最大展开的宽度*/
        }
    }

    @keyframes right {
        from {
            width: 250px;
        }

        to {
            display: none;
            ;
            width: 0px;
        }
    }




    .content {
        background-color: #cabcbc;
        width: 100px;
        height: 100%;
        border-radius: 15px;

    }
</style>

<body>

    <div id="vapp" class="app">

        <div class="cad">{{ msg}}

            <button @click="catVis()">显示</button>
        </div>
        <div class="cad">

            <div class="content" :class="{
                'open': visible,
                'close': !visible
            }">
                你的内容
            </div>
        </div>
        <div class="cad">cc</div>


    </div>

    <script>


        let vm = new Vue({
            el: '#vapp',
            data() {
                return {
                    visible: false,
                    msg: 'hello world'
                }
            },
            methods: {
                catVis() {
                    vm.visible = !vm.visible
                    console.log(vm.visible);
                }
            }
            , mounted() {
                console.log('init app');
            }
        })


    </script>


</body>

</html>