前端动画实现
动画的基本原理
什么是动画?
- 动画是通过快速、连续排列、彼此差异极小的、制造错觉的过程
常见的前端动画技术
- Sprite动画、CSS动画、JS动画、SVG动画和WebGL动画
计算机动画概念
计算机图形学:
是计算机视觉的基础,涵盖点、线、面、体、场的数学构造方法
计算机动画原理
- 动画多么简单都需要定义两个基本状态,也就是开始状态和结束状态。没有了两个状态就不可以填补两者之间的空白,做不出动画效果。
帧和帧率
帧:连续百年换的多张画面,其中的每一幅画面都是一帧
帧率:用于度量一定时间段内的帧数,通常的测量单位是FPS [一秒x张]
- 帧率和人眼:人眼10-12FPS会认为画面是连贯的,因为视觉暂留现象;但对于游戏而言,30FPS会感到明显卡顿,需要60FPS
空白的补全方式
补间动画
- 类比浏览器[keyframe, transition]
逐帧动画
- CSS的Step的逐帧动画实现
前端动画分类
CSS动画
定义
是一种样式表语言,描述HTML或者XML类的语言
常用的实现方式:CSS animation
- animation-name指定应用的一系列动画,每个名称代表一个由keyframes定义的动画序列
- animation-duration指定一个动画周期的时长
- animation-timing-function属性定义CSS动画在每一个动画周期中执行的节奏
- animation-delay属性定义了延时多少时间开始
- animation-iteration-count属性定义了在结束前运行的次数
- animation-direction属性指示了动画是否反向播放
- animation-fill-mode属性指示了动画在执行之前和之后如何将样式应用于其目标
- animation-play-state属性定义一个动画是否运行或者暂停
CSS的形体变换 [Transform]:只能转换由盒模型定位的元素
- transform-origin:指定原点的位置默认值为元素中心,可以被移动。可以使用该属性进行旋转、缩放和倾斜
- translate:移动【指定位移长度{纵向和横向两个}】
- scale:缩放【你需要指定缩放比例{有横向比例和纵向比例,都需要声明}和缩放中心】
- skew:倾斜【你需要指定倾斜角度{有水平方向的倾斜角度和垂直方向的倾斜角度}】
- Transition API在dom加载完成或者class发生变化的时候触发
- transform-origin:指定原点的位置默认值为元素中心,可以被移动。可以使用该属性进行旋转、缩放和倾斜
keyframe实现 [关键帧法]
- 和transition相比,该方法可以控制动画序列的中间步骤
优点与缺点
优点:简单、高效,声明式,不依赖主线程,采用GPU简单的控制keyframe、animation的播放和暂停
缺点:不能动态修改或者定义动画内容,不同的动画无法实现同步,多个动画彼此无法堆叠
使用场景
简单的h5宣传页
推荐库:animation.css和shake.css
svg动画
定义
svg是基于XML的矢量图形来描述语言,可以很好的和CSS和JS较好的配合,实现方式有SMIL\JS\CSS
优点与缺点
优点:通过矢量元素实现动画,不同的屏幕下都可以获得较好的清晰度,可以用于实现一些特殊的效果,比如描字、形变、墨水扩散等
缺点:使用复杂,容易带来性能问题
JS动画
JS可以实现复杂的动画,也可以操作canvas动画API上来进行绘制
优点与缺点
优点:
- 灵活,可以调节若干函数,参数更灵活
- 可以做的比CSS的keyframe的粒度更细
- 可以做多个状态的转化,这在css中是很难做到的
缺点:
- 调优方式比CSS复杂
- 对于性能较差的浏览器,CSS可以做到优雅降级,而JS必须得兼容
总结
UI元素采用较小的独立状态的时候使用CSS
需要对动画进行大量控制的时候使用JS
在特定场景下可以使用SVG,使用CSS和JS进行对SVG的操作
前端动画实现
我们在这里主要阐述偏JS的动画
动画函数
draw: 绘制函数
可以把draw想象成一直画笔,随着函数的执行,这个画笔的函数回反复被调用,并传入当前持续进度progress,progress是一个介于0-1之间的数字
easing: 缓动函数
缓动函数决定了时间在线性增长过程中,实际的执行进度的变化,是一个表达式duration: 持续时间
动画的持续时间,单位是毫秒requestAnimationFrame: 浏览器重绘时开始做,与浏览器的重绘保持一致,如果使用setTimeout可能会有该现象:浏览器重绘较慢,导致setTimeout不同步执行导致丢帧现象
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function animate ({easing, draw, duration}) {
let start = performance.now()
return new Promise(resolve => {
requestAnimationFrame(function animate (time) {
let timeFraction = (time - start) / duration
if (timeFraction > 1) timeFraction = 1
let progress = easing(timeFraction)
draw(progress)
if (timeFration < 1) {
requestAnimationFrame(animate)
} else {
resolve()
}
})
})
}
JS执行动画的核心思想
$$
\Delta r = \Delta v \Delta t
$$
简单动画
匀速运动
1 | const ball = document.querySelector('.ball') |
重力
1 | const ball = document.querySelector('.ball') |
摩擦力
1 | const ball = document.querySelector('.ball') |
平抛
1 | const ball = document.querySelector('.ball') |
拉弓
1 | const ball = document.querySelector('.ball') |
贝塞尔曲线
$$
\Beta(t) =\Rho_{0}(1-t)^3+3\Rho_{1}t(1-t)^2+3\Rho_{2}t^2(1-t)+\Rho_{3}t^3 ,t\in[0,1]
$$
用专门的网站来找出点来代入贝塞尔曲线
弹跳小球
使用缓动函数
使用自动衰减[更推荐使用]
椭圆运动
1 | const ball = document.querySelector('.ball') |
相关实践
- Lottie:解析AE动画