Loading

css-Animation分享

nsplknsplk

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

CSS-Animation浅析

分享人:蔺凯

目录

  • css动画之Transition

 

  • css动画之Animation

 

  • 简单动画的性能

 

  • css动画FPS帧率测试

 

  • (ps)电影24帧为什么不卡顿

 

 

 

 

 

属性 描述
transition 简写属性,在一个属性中设置四个过渡属性
transition-property 规定应用过渡的CSS属性名称
transition-duration 规定过渡效果持续时间。默认是0
transition-timing-function 规定过渡效果时间曲线。默认是"ease"
transition-delay 规定过渡效果何时开始。默认是0

一、Transition 过渡

1. Transition 过渡触发方式

  伪类触发::hover : focus  :checked  :active

  js触发:toggleClass

2. 以下情况下,属性值改变不能产生过渡效果

  • background-image,如url(a.jpg)到url(b.jpg)(与浏览器支持相关,有的浏览器不支持)等,浏览器支持情况
  • float浮动元素
  • height或width使用auto值
  • display属性在none和其他值(block、inline-block、inline)之间变换
  • position在static和absolute之间变换

transition的优点在于简单易用,但是它有几个很大的局限

(1)transition需要事件触发,所以没法在网页加载时自动发生。

(2)transition是一次性的,不能重复发生,除非一再触发。

(3)transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。

(4)一条transition规则,只能定义一个属性的变化,不能涉及多个属性。

 

CSS Animation就是为了解决这些问题而提出的

贝塞尔曲线定义:

 

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。 曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。

它是 animation-timing-function 和transition-timing-function 中一个重要的内容。

贝塞尔曲线原理

 满足AE/AB = BF/BE = CG/CD = EH/EF = FI/FG = HJ/HI条件的所有J点所形成的轨迹就是三阶贝塞尔曲线

  css3定义规则cubic-bezier (p0,p1,p2,p3)

css中贝塞尔曲线常见的值

ease:cubic-bezier(.25, .1, .25, 1)

liner:cubic-bezier(0, 0, 1, 1) / cubic-bezier(1, 1, 0, 0)

ease-in:cubic-bezier(.42, 0, 1, 1)

ease-out:cubic-bezier(0, 0, .58, 1)

ease-in-out:cubic-bezier(.42, 0, .58, 1)

In Out . Back(来回的缓冲效果):cubic-bezier(0.68, -0.55, 0.27, 1.55)

关键帧(@keyframes)

  • 关键帧(keyframes) - 定义动画在不同阶段的状态。
  • 动画属性(properties) - 决定动画的播放时长,播放次数,以及用何种函数式去播放动画等。(可以类比音视频播放器)
  • css属性 - 就是css元素不同关键帧下的状态。
 @keyframes dropdown {
    0% { top: 0; left:0px;}
    30% { top: 300px; left:0px;}
    50% { top: 150px; left:0px;}
    70% { top: 300px; left:0px;}
    80% { top: 0px;  left:-200px;}
    100% { top: 0px;  left:0px;}
  }

二、Animation

 animation-name用来调用@keyframes定义好的动画,与@keyframes定义的动画名称一致

 animation-duration :指定元素播放动画所持续的时间

 animatino-timing-function : 和transition中的transition-timing-function 中的值一样。根据上面@keframes中分析的animation中可能存在多个小动画,因此这里的值设置是针对每一个小动画所在时间范围内的属性变换速率。

 animation-delay定义在浏览器开始执行动画之前等待的时间。

 animation-iteration-count:定义动画的播放次数,其通常为整数,默认是1,;取值为infinite,动画将无限次的播放。

 animation-direction:主要用来设置动画播放方向,其主要有两个值:

  • normal 默认值,如果设置为normal时,动画每次循环都是向前(即按顺序)播放
  • alternate(轮流),动画播放在第偶数次向前播放,第奇数次向反方向播放(animation-iteration-count取值大于1时设置有效)

 

animation-fill-mode 这个 CSS 属性用来指定在动画执行之前和之后如何给动画的目标应用样式。

 

  • none(回到动画没开始时的状态),

  • forwards(动画结束后动画停留在结束状态),

  • backwords(动画回到第一帧的状态),

  • both(根据animation-direction轮流应用forwards和backwards规则),注意与iteration-count不要冲突(动画执行无限次)


animtion-play-state:属性是用来控制元素动画的播放状态。其主要有两个值:​

  • running,可以通过该值将暂停的动画重新播放,这里的重新播放不是从元素动画的开始播放,而是从暂停的那个位置开始播放。

  • paused,暂停播放

 

animation-iteration-count

 

infinite | <number>[,infinite | <number>]

animation-direction

<single-animation-direction> = normal | reverse | alternate | alternate-reverse

  • normal: 正向播放
  • reverse: 反向播放
  • alternate: 若动画只播放一次,则和正向播放一样。若播放两次以上,偶数次效果为反向播放
  • alternate-reverse: 若动画只播放一次,则和反向播放一样。若播放两次以上,偶数次效果为正向播放

animation-fill-mode

<single-animation-fill-mode> = none | forwards | backwards | both
div:hover {
  animation-name: rainbow;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-delay: 1s;
  animation-fill-mode:forwards;
  animation-direction: normal;
  animation-iteration-count: 3;
}

 

div:hover {
  animation: 1s 1s rainbow linear 3 forwards normal;
}

序列进入

 

  漂浮的白云主要通过远景白云和近景白云来实现立体漂浮效果。远景和近景分别使用两张背景图片,通过改变其背景定位来实现白云移动效果,通过设置不同的动画持续时间来实现交错漂浮的效果

正方体

一般情况下,主线程负责:

  • 运行 JavaScript;
  • 计算 HTML 元素的 CSS 样式;
  • 页面的布局;将元素绘制到一个或多个位图中;
  • 将这些位图交给合成线程。

 

合成线程负责:

  • 通过 GPU 将位图绘制到屏幕上;
  • 通知主线程更新页面中可见或即将变成可见的部分的位图;
  • 计算出页面中哪部分是可见的;
  • 计算出当你在滚动页面时哪部分是即将变成可见的;
  • 当你滚动页面时将相应位置的元素移动到可视区域。

渲染一个网页需要两个重要的线程来共同完成

三、简单动画的性能

图中橘黄色部分代表操作相对较慢,消耗较大;

蓝色部分代表操作相对较快,消耗较小

<style>
#foo {
  height: 100px;
  width: 100px;
  background: red;
  transition: height 1s linear;
}
#foo:hover {
  height: 200px;
}
</style>
<body>
  <div id="foo"></div>
</body>

从上图我们可以看到,浏览器的两个线程在来回地切换工作,而且橘黄色出现次数较多,这意味着浏览器需要处理相当多的工作。

对于浏览器而言,由于元素的高度一直在变化,因此这个动画的每一帧中,都需要重新布局 ——> 绘制页面 ——> 将新的位图加载到 GPU 中 ——> 显示。而其中加载到 GPU 是一个相对缓慢的操作。

height

 

<style>
#bar {
  height: 100px;
  width: 100px;
  background: red;
  transition: transform 1s linear;
}
#bar:hover {
  transform: scale(2);
}
</style>
<body>
  <div id="bar"></div>
</body>

由此我们可以看到,两个线程来回切换的情况并不多,橘黄色部分出现的次数也较少,蓝色部分居绝大部分,这意味着这个动画效果相较于上面的要流畅很多。

在定义中,transform 是不会使浏览器产生重新排版的,因此 transform 不会影响原本的布局,以及周围的元素。它会将定义的元素作为一个整体进行缩放、移动或旋转等。

基于 transform 这类的特性,浏览器在渲染页面时可以节省很多不必要的开支,例如重新布局和将位图传给 GPU 等工作,这样就使得动画更有效率。

translate

优化 CSS 动画,先给出最后的一个优化步骤方案:

  1. 精简 DOM ,合理布局
  2. 使用 transform 代替 left、top,减少使用耗性能样式
  3. 控制频繁动画的层级关系
  4. 使用 dev-tool 时间线 timeline 观察,找出导致高耗时、掉帧的关键操作

Text

height

transform

transform

 

height

 

在需要写动画时,我们需要选择合适的方案,最好是选择 scale()rotate()transalte() 等,因为他们具有更好的性能。

通过这个按钮,可以开启页面实时 Frame Rate (帧率) 观测及页面 GPU 使用率。

  • 这个只能一次观测一到几个页面,而且需要人工实时观测
  • 数据只能是主观感受,并没有一个十分精确的数据不断上报或者被收集

chorme开发工具

四、动画FPS简单测试

二、 Frame Timing API

Frame Timing API 是 Web Performance Timing API 标准中的其中一位成员。

Web Performance Timing API 是 W3C 推出的一套性能 API 标准,用于帮助开发者对网站各方面的性能进行精确的分析与控制,提升 Web 网站性能。

它包含许多子类 API,完成不同的功能,大致如下(摘自使用性能API快速分析web前端性能,当然你也可以看英文原版介绍:Web Performance Timing API ):

requestAnimationFrame 方法告诉浏览器您希望执行动画并请求浏览器调用指定的函数在下一次重绘之前更新动画。

当你准备好更新屏幕画面时你就应用此方法。这会要求你的动画函数在浏览器下次重绘前执行。回调的次数常是每秒 60 次,大多数浏览器通常匹配 W3C 所建议的刷新率。

三、

var rAF = function () {
    return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        }
    );
}();
 
var frame = 0;
var allFrameCount = 0;
var lastTime = Date.now();
var lastFameTime = Date.now();
 
var loop = function () {
    var now = Date.now();
    var fs = (now - lastFameTime);
    var fps = Math.round(1000 / fs);
 
    lastFameTime = now;
    // 不置 0,在动画的开头及结尾记录此值的差值算出 FPS
    allFrameCount++;
    frame++;
 
    if (now > 1000 + lastTime) {
        var fps = Math.round((frame * 1000) / (now - lastTime));
        console.log(`${new Date()} 1S内 FPS:`, fps); 
        frame = 0;
        lastTime = now;
    };
 
    rAF(loop);
}
 
loop();

正常而言 requestAnimationFrame 这个方法在一秒内会执行 60 次,也就是不掉帧的情况下。假设动画在时间 A 开始执行,在时间 B 结束,耗时 x ms。而中间 requestAnimationFrame 一共执行了 n 次,则此段动画的帧率大致为:n / (B – A)。

测试页面,Solar System

浏览器硬件加速

将浏览器的渲染过程交给GPU处理,而不是使用自带的比较慢的渲染器。这样就可以使得animation与transition更加顺畅。

.cube {
   -webkit-transform: translateZ(0);
   -moz-transform: translateZ(0);
   -ms-transform: translateZ(0);
   -o-transform: translateZ(0);
   transform: translateZ(0);
   /* Other transform properties here */
}

transform: translate3d(0, 0, 0);
如何开启 GPU 加速?
  1. 3D 或透视变换(perspective,transform) CSS 属性
  2. 使用加速视频解码的video元素
  3. 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 canvas 元素
  4. 混合插件(如 Flash)
  5. 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
  6. 拥有加速 CSS 过滤器的元素

只对我们需要实现动画效果的元素应用以上方法,如果仅仅为了开启硬件加速而随便乱用,那是不明智的。

小心使用这些方法,如果通过你的测试,结果确是提高了性能,你才可以使用这些方法。使用GPU可能会导致严重的性能问题,因为它增加了内存的使用,而且它会减少移动端设备的电池寿命。

Question : 是不是游戏、动画帧数一般要到 60 帧每秒才流畅,而过去的大部分电影帧数只有 24 帧每秒却没有不流畅感?

第一帧

电影第一帧

游戏动画第二帧

  • 第一个原因因为电影和游戏的画面生成方式的本质不同造成的,电影的画面是拍摄的实际场景,在快门时间内胶片/传感器持续曝光,这一段时间里人物场景的变化都会被拍到胶片/传感器上,每隔一段时间换下一张胶片再曝光一段时间。
  • 而游戏的画面则是由显卡生成的,显卡通过计算生成一帧画面,生成完毕后再计算下一帧,这样每一帧都是清晰的,不会有模糊,像上面图中的那个圆,不管他的移动速度是快是慢,显卡只计算两帧画面,中间的移动轨迹一概不会显示,我们看到物体就好像老版西游记里面孙悟空施一个法术“就”的一声飞过去了。有了残影,你就不会觉得画面卡了,这就是电影的效果

电影《星际穿越》画面,可以看到很明显的动态模糊。

  • 第二个原因就是电影的帧数是稳定的,他固定每隔1/24秒换一次画面,画面出现频率是固定的而游戏则是不稳定的。帧生成时间是主要因素,也就是说两帧之间的间隔时间。卡顿的显卡,可能前半秒生成了59帧画面,后半秒就只有1帧画面了

电影里面一米一米移动的时候,每帧的画面是清晰,十米十米移动的时候,动作就会出现拖影,给人以动感的效果,连贯而不卡。

加入动作模糊等特效, 对画面中高速运动的物体加上人为模糊,从而实现和电影画面相似的质感。 在打开动态模糊的情况下,30帧和60帧的视觉流畅度差异极小。

游戏的卡顿分很多原因。RTS游戏中单位出现过多,CPU计算能力不够,会卡,游戏特效变好,显卡算不过来,会卡,切换地图读硬盘,会卡,场景太大内存放不下,会卡。例如切换地图读取硬盘时候的卡,就和显卡性能(帧数)无关,这时候即便帧数再高,硬盘性能不够了,还是会卡,这点用机械硬盘玩游戏的会有体会。

第三个原因,就是电影只需要看,只要画面流畅就行了,而游戏是涉及到操作的,如果FPS过低,或者帧生成时间过长,就会使得操作更加不流畅。先是人眼看到一帧画面,然后才能进行对应的操作,再体现到下一帧的画面上,一个操作需要数帧才能完成。这样一来,当FPS降低一半,也就是帧生成时间增加一倍,一个操作所需的时间会增加数倍,带给玩家的直观感受就是,操作不跟手了,卡了。特别是当帧生成时间不稳定的时候,不跟手的情况就越发明显了。

所以当帧数提高的时候,不简简单单的是画面变流畅了,而是能明显感受到,整个游戏的操作都变得更加的流畅了。

谢 谢 大 家!

Made with Slides.com