在网页中,实现动画无外乎两种方式。
1. CSS3 方式,也就是利用浏览器对CSS3 的原生支持实现动画;
2. 脚本方式,通过间隔一段时间用JavaScript 来修改页面元素样式来实现动画。
接下来我们就分别介绍这两种方式的原理,让大家先对这两种方式有一个直观认识,了解各自的优缺点。

CSS3 的方式下,开发者一般在css 中定义一些包含CSS3 transition 语法的规则。在某些特定情况下,让这些规则发生作用,于是浏览器就会将这些规则应用于指定的DOM元素上,产生动画的效果。这种方式毫无疑问运行效率要比脚本方式高,因为浏览器原生支持,省去了JavaScript 的解释执行负担,有的浏览器(比如Chrome 浏览器)甚至还可以充分利用GPU 加速的优势,进一步增强了动画渲染的性能。不过CSS3 的方式并非完美,也有不少缺点。
首先, CSS3 Transition 对一个动画规则的定义是基于时间和速度曲线( Speed Curve)的规则。换句话来说,就是CSS3 的动画过程要描述成“在什么时间范围内,以什么样的运动节奏完成动画” 。

<!DOCTYPE html>
<html><head><style>
.sample {background: red;position: absolute;left: 0px;width: 100px;height: 100px;transition-property: left;transition-duration: 0.5s;transition-timing-function: ease
}
.sample:hover {left: 420px;
}</style></head><body><div class="sample" /></body>
</html>

在上面的例子中, sample 类的元素定义了这样的动画属性:“ left 属性会在0.2 秒内以ease 速度曲线完成动画” 。transition 只定义了动画涉及的属性、时间和速度曲线,并不定义需要修改的具体值。sample 类的left 属性默认值为0 ,当鼠标移到sample 类元素上时, left 属性就拥有新的值420px 。这时候transition 定义的规则发生作用,让left 属性以ease 速度曲线在0.2 秒
的时间完成从0 变成420px 的转化过程,这个过程中,用户看到的就是sample 类元素向右移动420 个像素的动画过程。
        因为CSS3 定义动画的方式是基于时间和速度曲线,可能不利于动画的流畅,因为动画是可能会被中途打断的,在上面的例子中,鼠标移到sample 类元素上的时候开始动画,但是在0.2 秒的动画时间内,用户的鼠标可能会移出这个sample 类元素,这时候CSS3 还会以ease 速度曲线的节奏让sample 类元素回到原位。从用户体验角度来说,中途sample 类元素回到原位的动作,语义上是“取消操作”的含义,但却依然以同样的时间和ease 节奏来完成“取消操作”的动画,这并不合理。

时间和速度曲线的不合理是CSS3 先天的属性,更让开发者头疼的就是开发CSS3 规则的过程,尤其是对transition-duration 时间很短的动画调试,因为CSS3 的transition 过程总是一闪而过,捕捉不到中间状态,只能一遍一遍用肉眼去检验动画效果,用CSS3做过复杂动画的开发者肯定都深有体会。虽然CSS3 有这样一些缺点,但是因为其无与伦比的性能,用来处理一些简单的动画还是不错的选择。

相对于CSS3 方式,脚本方式最大的好处就是更强的灵活度,开发者可以任意控制动画的时间长度,也可以控制每个时间点上元素渲染出来的样式,可以更容易做出丰富的动画效果。脚本方式的缺点也很明显,动画过程通过JavaScript 实现,不是浏览器原生支持,消耗的计算资源更多。如果处理不当,动画可能会出现卡顿滞后现象,本来使用动画是为了创造更好的用户体验,如果出现卡顿,反而对用户体验带来不好的影响。最原始的脚本方式就是利用setlnterval 或者setTimeout 来实现,每隔一段时间一个指定的函数被执行来修改界面的内容或者样式,从而达到动画的效果。

<!DOCTYPE html>
<html><head><style>
#sample {position: absolute;background: red;width: 100px;height: 100px;
}</style></head><body><div id="sample" /><script type="text/javascript">
var animatedElement = document.getElementById("sample");
var left = 0;
var timer;
var ANIMATION_INTERVAL = 16;timer = setInterval(function() {left += 10;animatedElement.style.left = left + "px";if ( left >= 400 ) {clearInterval(timer);}
}, ANIMATION_INTERVAL);</script></body>
</html>

在上面的例子中,有一个常量ANIMATION INTERVAL 定义为16 , setlnterval 以这个常量为间隔,每16 毫秒计算一次sample 元素的left 值,每次都根据时间推移按比例增加left 的值,直到left 大于400 。为什么要选择16 毫秒呢?因为每秒渲染60 帧(也叫60fps, 60 Frame Per Second)会给用户带来足够流畅的视觉体验,一秒钟有1000 毫秒, 1000 /60 =16 ,也就是说,如果我们做到每16 毫秒去渲染一次画面,就能够达到比较流畅的动画效果。对于简单的动画, setlnterval 方式勉强能够及格,但是对于稍微复杂一些的动画,脚本方式就顶不住了,比如渲染一帧要花去超过32 毫秒的时间,那么还用16 毫秒一个间隔的方式肯定不行。实际上,因为一帧渲染要占用网页线程32 毫秒,会导致setlnterval根本无法以16 毫秒间隔调用渲染函数,这就产生了明显的动画滞后感,原本一秒钟完成的动画现在要花两秒钟完成,所以这种原始的setlnterval 方式是肯定不适合复杂的动画的。
       出现上面问题的本质原因是setlnterval 和setTimeout 并不能保证在指定时间间隔或者延迟的情况下准时调用指定函数。所以可以换一个思路,当指定函数调用的时候,根据逝去的时间计算当前这一帧应该显示成什么样子,这样即使因为浏览器渲染主线程忙碌导致一帧渲染时间超过16 毫秒,在后续帧谊染时至少内容不会因此滞后,即使达不倒60fps 的效果,也能保证动画在指定时间内完成。

<!DOCTYPE html>
<html><head><style>
#sample {position: absolute;background: red;width: 100px;height: 100px;
}</style></head><body><div id="sample" /><script type="text/javascript">var lastTimeStamp = new Date().getTime();
function raf(fn) {var currTimeStamp = new Date().getTime();var delay  = Math.max(0, 16 - (currTimeStamp - lastTimeStamp));var handle = setTimeout(function(){fn(currTimeStamp);}, delay);lastTimeStamp = currTimeStamp;return handle;
}var left = 0;
var animatedElement = document.getElementById("sample");
var startTimestamp = new Date().getTime();
function render(timestamp) {left += (timestamp - startTimestamp) / 16;animatedElement.style.left = left + 'px';if (left < 400) {raf(render);}
}raf(render);</script></body>
</html>

在上面定义的raf 中,接受的fn 函数参数是真正的渲染过程, raf 只是协调渲染的节奏。raf 尽量以每隔16 毫秒的速度去调用传递的fn 参数,如果发现上一次被调用时间和这一次被调用时间相差不足16 毫秒,就会保持16 毫秒一次的渲染间隔继续,如果发现
两次调用时间间隔已经超出了16 毫秒,就会在下一次时钟周期立刻调用fn 。上面的render 函数中根据当前时间和开始动画的时间差来计算sample 元素的left 属性,这样无论render 函数何时被调用,总能够渲染出正确的结果。
最后,我们将render 作为参数传递给raf ,启动了动画过程

转载于:https://www.cnblogs.com/majiang/p/9691950.html

HTML动画 request animation frame相关推荐

  1. Android动画开发——Animation动画效果

    动画类型 Android的animation由四种类型组成 XML中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面 ...

  2. iOS 核心动画 Core Animation浅谈

    代码地址如下: http://www.demodashi.com/demo/11603.html 前记 关于实现一个iOS动画,如果简单的,我们可以直接调用UIView的代码块来实现,虽然使用UIVi ...

  3. Unity 游戏入门 九、 精灵动画 Sprite Animation

    1.Animator 为了在游戏对象上有动画,需要添加一个组件Animator. 在工程窗口中,双击Robot  预制体. 如图所示,添加Animator组件. 2.Creating a New Co ...

  4. android 属性动画伸缩,Android动画开发——Animation动画效果详解

    在Android中,分别可以在xml中定义Animation,也可以在程序代码中定义. 动画类型Android的animation由四种类型组成 XML中alpha渐变透明度动画效果 scale渐变尺 ...

  5. 属性动画-Property Animation之ViewPropertyAnimator 你应该知道的一切

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52381558 出自[zejian的博客] 关联文章: 走进绚烂多彩的 ...

  6. Unity3d动画脚本 Animation Scripting(深入了解游戏引擎中的动画处理原理--旧的动画系统)

    (来自:http://blog.sina.com.cn/s/blog_409cc4b00100qmgz.html) 也许这一篇文章的内容有点枯燥,但我要说的是如果你想深入的了解游戏引擎是如何处理动画片 ...

  7. Unity3d动画脚本 Animation Scripting

    Unity3d动画脚本 Animation Scripting(深入了解游戏引擎中的动画处理原理) 也许这一篇文章的内容有点枯燥,但我要说的是如果你想深入的了解游戏引擎是如何处理动画片断或者素材并 让 ...

  8. 走进绚烂多彩的属性动画-Property Animation(上篇)

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52273733 出自[zejian的博客] 关联文章: 走进绚烂多彩的 ...

  9. 设置按键退出python pygame动画(animation)程序,python检测键盘按键

    功能:设置按键退出python pygame动画(animation)程序,python3.6检测键盘按键 pygame运行起来,不弄个强行终止都刹不住....为此研究了一下怎么退出. 实现的效果是: ...

最新文章

  1. WordCount扩展与优化
  2. 老大,你为什么在代码中要求我们使用LocalDateTime而不是Date?
  3. gitlab 安装报错:Could not find modernizr-2.6.2 in any of the sources
  4. 转向语句 goto语句
  5. 判断字符串是否为回文(C语言 顺序栈)
  6. REVERSE-PRACTICE-BUUCTF-15
  7. @开发者,第二届马栏山杯国际音视频算法大赛高分攻略请查收,心动大奖等你来战!...
  8. hibernate 映射 数据库number 映射为 double 为空 报错问题
  9. python matplotlib调整图像比例
  10. 飞机大战java_Java飞机大战
  11. 最新WIN10系统封装教程2019系列(一)——定制母盘
  12. 为什么要写书?出版图书有哪些好处?
  13. 一个机械研究生在计算机与机械之间的徘徊与思考-(下)之填坑
  14. Excel 表格实现多列排序
  15. 取得df的列名的列表,取得df的列宽,把df的列融入成为其他df的列
  16. 线性表之顺序表的基本操作
  17. Docker学习四--Harbor私有仓库搭建
  18. LaTex使用技巧10:公式中的各种英文字体
  19. 用scc-loader实现模块化css编程
  20. Tikz教程:一个异步FIFO设计步骤示意图的画法

热门文章

  1. 调试 后台 ajax post 对应的php的方法
  2. jQuery插件thickbox在ie下垂直居中问题
  3. c语言定义字符类型变量的关键字,C语言数据类型
  4. go linux 源码编译环境,Linux 源码安装 GO 环境
  5. TensorFlow基本计算单元:代码示例
  6. html5 graphics with svg css3,HTML5 GRAPHICS WITH SVG AND CSS3
  7. windows增量到linux,Beyond Compare 3在windows和linux下实现提取增量包
  8. java perl_在Java中调用Perl脚本
  9. 科软2020计算机科学与技术,2020新高考 报考计算机类专业怎么选科
  10. stream流map 多个字段_stream流根据对象指定字段去重