Get Started
• 动画的原理
• 浏览器渲染原理
• CSS动画优化
• transform全解
• transition过渡
动画
• 定义
有许多静止的画面(帧)
以一定的速度(如每秒30张)连续播放时
肉眼因视觉残像产生错觉而误以为是活动的画面
• 概念
帧:每个静止的画面都叫做帧
播放速度:每秒24帧(影视)或者每秒30帧(游戏)
一个最简单的例子
• 将一个div从左往右移动
• 原理
每过一段时间(用setInerval做到)
将div移动一小段距离
知道移动到目标地点
• 注意性能
绿色表示重新绘制(repaint)
CSS渲染过程一次包含布局,绘制,合成
其中布局和绘制有可能被省略
var n = 1
var id setInterval(() => {
if (n <= 200) {
demo.style.left = n + 'px'
n = n + 1
} else {
clearInterval(id)
}
}, 1000 / 60)
前端高手不用left做动画
• 用transform(变形)
• 原理
transform: translateX(0=>200px)
直接修改会被合成,需要等一会修改
transition过度属性可以自动脑部中间帧
transform只在页面刷新,动作开始动作结束时渲染。因此性能更高。
• 注意性能
并没有repaint(重新绘制)
比left性能好
#demo {
width: 100px;
height: 100px;
border: 1px solid red;
position: relative;
left: 0;
}
#demo.end {
transform: translateX(200px);
}
JS
steTimeout(()=>{
demo.classList.add('end')
},3000)
浏览器渲染原理
参考文章
• Google团队写的文章
渲染树构建,布局及绘制
渲染性能
使用transform来实现动画
• 查看CSS个属性触发什么
CSSTriggers.com
浏览器渲染过程
• 步骤
根据HTML构建HTML树(DOM)
根据CSS构成CSS树(CSSDOM)
将两棵树合并成一颗渲染树(render tree)
Layout布局(文档流,盒模型,计算大小和位置)
paint绘制(把边框颜色、文字眼色、阴影等画出来)
compose合成(根据层叠关系展示画面)
如何更新样式
• 一般我们用js来更新样式
比如 div.style.background = 'red'
比如 div.style.display = 'none'
比如 div.classList.add('red')加样式不如加类
比如 div.remove()直接删掉节点
• 这些方法有什么不同
有三种不同的渲染方式
- JS/CSS>样式>布局>绘制>合成
更新方式:全走
div.remove()会触发当前消失,其他元素relayout - JS/CSS>样式>布局>绘制>合成
更新方式:跳过layout
改变背景颜色,直接repaint+composite - JS/CSS>样式>合成
更新方式:跳过layout和paint
改变transform,只需要composite
注意必须全屏查看效果,在iframe里看有问题
到底哪个样式,怎么样更新样式:https://csstriggers.com/
CSS动画优化
答案都在Google写的文章里
• JS优化
使用requestAnimationFrame代替setTimeout或setInterval
• CSS优化
使用will-change或translate
transform全解
https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform
• 四个常用功能
位移 translate
缩放 scale
旋转 rotate
倾斜 skew
• 经验
一般都需要配合transition过度
inline元素不支持transform,需要先变成block
translate
• 常用写法
translateX(<length-perventage>)
translateY(<length-perventage>)
translate(<length-perventage>,<length-perventage>?)
translateZ(<length>)
且父容器perventage
Translat3d(x,y,x)
• Note
perspective: 1000px;
视图的原点在中心,范围是1000px
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
定位元素居中,完美
transform: scaleX(1.5);
变高变瘦
• border的宽度也会跟着变化
• 经验
要学会看懂MDN的语法示例
Translate(-50%,-50%)可做绝对定位元素的居中
scale
• 常用写法
scaleX(<number>)
scaleY(<number>)
scale(<number>,<number>)
• 经验
使用较少,因为会出现模糊
rotate
• 常用写法
rotate([<angle>|<angle>])
rotateZ([<angle>|<angle>])
rotateX([<angle>|<angle>])
rotateY([<angle>|<angle>])
rotate3d
• 经验
一般用于360°旋转制作loading
用到是再搜索rotate MDN看文档
skew
• 常用写法
skewX([<angle>|<zero>])
skewY([<angle>|<zero>])
skew([<angle>|<zero>],[<angle>|<zero>])
• 经验
使用较少,用到再搜文档
transform多重效果
• 组合使用
transform: scale(0.5) translate(-100%,-100%)
transform: none;
取消所有
transition过渡
• 作用:补充中间帧
• 语法
transition:属性名 市场过渡方式 延迟
transition:left 200ms liner
可以用逗号分隔两个不同属性
transition: left 200,top 200ms
可以用all代表所有属性
transition:all 200ms
过渡方式有:liner|ease|ease-in|ease-out|ease-in-out|cubic-bezier|step-start|step_end|steps
https://developer.mozilla.org/zh-CN/docs/Web/CSS/timing-function
• 注意:并不是所有属性都可以过渡
display:none=>block
没法过度
一般改成visibility:hidden=>visible
(过渡到看不见,位置还占着。)
background眼色可以过渡(因为颜色是个数值)
opacity透明度可以过渡,过渡到0的时候只是看不见,位置还占着。(需要demo,remove()把这个扔掉才会没有)
过渡必须要有起始
一般只有一次动画,或者两次。比如hover和非hover状态的过渡
如果还有中间点?
两种办法
• 使用两次transform
.a === transform ===> .b
.b === transform ===> .c
如何知道了中间点呢
用setTimeout或者监听transitionend事件
http://js.jirengu.com/buwah/1/edit?html,css,js,output
• 使用animetion
声明关键帧
添加动画
让动画停在最后一帧:加个forwards
http://js.jirengu.com/peran/1/edit?html,css,output
• keyframes语法
from to和百分数
@keframs slidein{
from{
transform(0%);
}
to{
transform(100%);
}
}
@keframs slidein{
0% { top: 0;left: 1; }
30% { top: 50px; }
68%, 72% { left: 50px; }
100% { top: 100px; left: 100%; }
}
• animation缩写语法
animation:时长|过渡方式|延迟|次数|方向|填充模式|是否暂停|动画名;
时长:1s或者1000ms
过渡方式:跟transition取值一样,如linear
次数:3或者2.4或者infinite
方向:reverse|laternate(常用)|alternate_reverse
填充模式: none|forwards|backwards|both
是否暂停: paused|tunning
以上所有属性都有对应的单独属性