使用css实现动画方法与动画性能分析

css3新增了transition与animation两种方式可实现动画,那么在出现transition与animation以前,有两种方式实现动画:一种是使用css的hover伪类属性方式,另一种是使用js改变css属性方式;接下来我会介绍transition与animation的使用方法以及解决了什么问题,最后会分析咱们为何使用transition与animation实现动画要比js方式性能要高效!javascript

transition的使用


咱们以前使用hover伪类实现动画,是如下效果:css

.div {
    width:100px;
    height:100px;
    background:red;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}
复制代码

能够看出元素的状态变化是当即发生,没有一个过渡的过程,也就是没有时间轴;那么css3新增的transition(过渡)也就是解决了这个问题;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

复制代码

如上图,加上transition,div状态的变化就有了一个过渡过程;
transition 是 transition-property(状态发生变化的属性),transition-duration(过渡所用的时间),transition-timing-function(过渡变化的速度) 和 transition-delay(延迟多长时间开始过渡) 的一个简写属性。
上例中,3s就是过渡所用时间,咱们没有设置transition-property,就会默认全部发生变化的状态都会过渡,若是咱们只须要某个特定属性发生过渡变化,只须要写明就能够了;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

复制代码

若是咱们想要多个属性一块儿过渡,而不是所有变化的属性过渡,可以使用逗号分隔开;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s, background 3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

复制代码

css3 还给过渡增长了延迟时间与过渡速度的功能;过渡速度经常使用的有ease(速度逐渐变慢,这是默认值)、linear(均速)、ease-in(以慢速开始)、ease-in-out(慢速开始、再快速、再慢速)、cubic-bezier函数(可自定义速度);
假如咱们想要width先过渡,2s后height再过渡,2s后颜色再过渡,可使用下面写法;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s, height 2s 3s ease-in-out, background 3s 5s ease-in-out;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

复制代码

transition须要注意的事项:

  • transition须要事件触发,好比hover事件,click事件,所以不能在网页加载时自动发生;
  • transition是一次性的,不能重复发生,触发屡次触发;
  • transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。 animation的出现就解决了transition上面的问题;

animation的使用


animation能够实现transiton的效果,看下面代码;html

.div {
    width:100px;
    height:100px;
    background:red;
}
.div:hover {
    
    animation: move 3s forwards;
}
@keyframes move {
    100% {
         background: green;
          width:200px;
          height:200px;
    }
}
复制代码

animation 比 transition更强大,不须要事件触发,能够进入页面就开始加载,也能够无限循环;

.div {
    width:100px;
    height:100px;
    background:red;
  animation: move 3s infinite alternate;
}
@keyframes move {
    100% {
         background: green;
          width:200px;
          height:200px;animation-name
    }
}
复制代码

animation是个复合属性,子属性有:

  • animation-name 动画的名字,就是上面的move,须要使用keyframes关键字定义move的效果;
  • animation-duration 动画的持续时间,就是上面的3s
  • animation-timing-function 动画的变化速度,和transition的animation-timing-function值是同样
  • animation-delay 动画延迟执行的时间
  • animation-direction 动画执行的方向;动画循环播放时,每次都是从结束状态跳回到起始状态,再开始播放;animation-direction能够改变这种循环方向,值有:normal、reverse、alternate、alternate-reverse
  • animation-iteration-count 动画执行的次数,能够是数字,也能够是infinite(无限循环);
  • animation-fill-mode 默认状况下动画结束之后,会当即从结束状态跳回到起始状态。若是想让动画保持在结束状态,须要使用animation-fill-mode属性,值为forward。
  • animation-play-state 动画是否运行或者暂停;running:当前动画正在运行;paused:当前动画以被中止;
    目前,IE 10和Firefox(>= 16)支持没有前缀的animation,而chrome不支持,因此必须使用webkit前缀。
.div {
    width:200px;
    height:200px;
    background:red;
    margin: 100px auto;
    -webkit-animation: move 3s infinite alternate;
    animation: move 3s infinite alternate;
}
@keyframes move {
  0% {
    background: red;
    transform: scale(0.4);
    }  
  50% {
    background: yellow;
    border-radius: 100%;
  }
  100% {
    background: green;
    transform: scale(1.5);
    }
}
复制代码

要分析动画优化,那不得不提下浏览器对页面的渲染原理;java

动画性能分析

浏览器对页面的渲染原理,可分为如下步骤: 1.根据HTML构建DOM树;
2.根据CSS构建CSSOM树;
3.将DOM树与CSSOM树合成一个渲染树(render tree);
4.Layout布局,包括文档流、盒模型、计算大小和位置;
5.Paint绘制,包括边框颜色、文字颜色、阴影等画出来;
6.Compose合成,根据层叠关系展现画面;
css3

当DOM或者CSSOM树被修改,以上过程再被从新执行一遍,这样才能计算出哪些像素在页面从新渲染;当页面从新渲染时,像素至屏幕管道中的关键点有如下5个部分;

可是不是每次渲染都会通过以上5个部分,有如下三种方式:

通常来讲,咱们会使用 JavaScript 来实现一些视觉变化的效果。好比用 jQuery 的 animate 函数作一个动画、对一个数据集进行排序或者往页面里添加一些 DOM 元素等。 若是您修改元素的“layout”属性,也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等),那么浏览器将必须检查全部其余元素,而后“自动重排”页面。任何受影响的部分都须要从新绘制,并且最终绘制的元素需进行合成。
你能够打开控制台中选择rendering,选中paint flashing(绘制,绿色高亮区域)、layout shift regions(布局,蓝色高亮区域)

能够看下面的例子:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style> div { width: 100px; height: 100px; background: red; float: left; } div:nth-child(2) { background: yellow; } div:nth-child(3) { background:black; } </style>
</head>
<body>
<div id="div"></div>
<div></div>
<div></div>
<script> let div = document.getElementById("div"); setInterval(()=>{ div.style.display='none' },1000) </script>
</body>
</html>

复制代码

执行代码以下:web

从上面能够看到,js引发了元素位置的变化,是页面渲染元素通过了layout、paint;

若是您修改“paint only”属性(例如背景图片、文字颜色或阴影等),即不会影响页面布局的属性,则浏览器会跳过布局,但仍将执行绘制。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 100px;
      height: 100px;
      background: red;
      float: left;
    }
    div:nth-child(2) {
      background: yellow;
    }
    div:nth-child(3) {
      background:black;
    }
    div:hover {
      background:deeppink;
    }
  </style>
</head>
<body>
<div id="div"></div>
<div></div>
<div></div>
</body>
</html>

复制代码

从上图能够看出,改变背景色会引发paint,可是不会引发layout;

若是您更改一个既不要布局也不要绘制的属性,则浏览器将跳到只执行合成。 这个最后的版本开销最小,最适合于应用生命周期中的高压力点,例如动画或滚动。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #div {
      width: 100px;
      height: 100px;
      background: red;
      margin: 100px auto;
      -webkit-animation: change 3s infinite alternate;
      animation: change 3s infinite alternate;
    }
    @keyframes change {
      0% {
        transform: translateX(100PX);
      }
      50% {
        transform: translateX(300PX);
      }
      100% {
        transform: translateX(500PX);
      }
    }
  </style>
</head>
<body>
<div id="div"></div>
</body>
</html>

复制代码

从上图中可看到动画只有刚开始加载的时候回paint,后面只是合成,并无paint了;

参考文档:css动画简介 animation tricks
结束语:感谢饥人谷,以上文章记录了本身在饥人谷的学习内容;chrome

相关文章
相关标签/搜索