CSS动画
动画的原理
其定义为:有许多静止的画面(帧),以一定的速度(如30张/s)连续播放时,肉眼因视觉残像产生的错觉,而误以为是活动的画面。
帧的概念
帧是指每一个静止的画面,一般影视作品的播放速度为24帧/s,由于游戏对于动画画面质量的要求,最易游戏最低为30帧/s。
我们举一个简单的描述CSS动画的例子:将一个div从左到右移动。 原理:每过一段时间(使用setInterval)将div移动一段距离,直到目标点。
第一种方法:demo相对定位,使用left移动,使用setInterval函数。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Document</title>
<style>
#demo{
width: 100px;
height: 100px;
border: 1px solid red;
position: relative;
left: 0;
}
</style>
</head>
<body>
<div id="demo"></div>
<script>
var n = 1
var id = setInterval(() => {
if (n <= 200) {
demo.style.left = n + 'px'
n = n + 1
} else {
clearInterval(id)
}
}, 1000 / 60)
</script>
</body>
</html>
注意:通过开发者工具之中绘制渲染模块发现在div在移动过程中,一直在渲染,性能不好。如何在使用开发者工具查看渲染情况? 答:先打开开发者工具——在任意选项上按esc,出现一个控制台,点击控制台中左上角的“┇”,选择点击“Rendering”,勾选第一个“Paint flashing”,即可展示渲染情况-显示绿色。
补充
浏览器的渲染原理:
步骤:————三棵树
- 根据HTML构建HTML树(DOM)
- 根据CSS构建CSS树(CSSOM)
- 将两棵树合并成一颗渲染树(render tree)
- layout布局(文档流、盒模型、计算大小和位置)
- Paint绘制(边框的颜色、文字颜色、阴影等画出来)
- Compose 合成(根据层叠关系展示画面)
如何更新样式呢? 答:一般我们都是使用JS来更新样式
例如:
div.style.backgroung = 'red'; 将背景改为红色
div.style.display = 'none'; 改为隐藏
div.classList.add = ('red') 添加一个'red'类。一般高手都是只添加类,不加样式。
div.remove() 直接删除节点
三种更新方式的不同
-
JS/CSS > 样式 > 布局 > 绘制 > 合成 例子:div.remove()会触发当前消失,其他元素relayout。
-
JS/CSS > 样式 > 绘制 > 合成 例子:改变背景的颜色。直接repaint+recompose
-
JS/CSS > 样式 > 合成 例子:改变transform,只需要composite就行。注意必须要在全屏状态看效果,在iframe里面看有bug。
可以在csstriggers.com 里面查看所有属性是什么流程。
CSS动画优化
在这边我们只简单举几个可行的方法。具体的优化内容,我之后会单独出一个文章谈谈。
- JS优化:使用requestAnimationFrame代替setTimeout或setInterval.
- CSS优化:使用will-change或translate。 我们回到之前做的将一个div从左到右移动,一般高手都不用left,还是使用transform:tranlate来移动div,从性能上来说,translate的渲染没有relayout和repaint,只有开始的样式和最后的合成,比left性能好很多。
CSS动画中常用的属性
tranform
transform有四个常用的功能:
- translate——位移
- scale——缩放
- rotate——旋转
- skew——倾斜
translate有以下几种写法:
- translateX()——正右负左
- translateY()——正上负下
- translateZ()——正近负远
- translate(x,y)
- translate3d(x,y,z) 注意事项:
- 学会看懂MDN文档的语法格式
- 绝对居中的写法:
.wrapper{
position:relative;
height:100px;
}
.x{
position:absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
scale
scale有下面写法:
- scaleX()——按照X轴缩放
- scaleY()——按照Y轴缩放 scale用的比较少,因为会导致图像变得模糊。
rotate
rotate的写法:
- rotateX()——绕着X轴旋转
- rotateY()——绕着Y轴旋转
- rotateZ()——绕着Z轴旋转
- rotate()
skew
使用方法:
- skewX()——绕着X轴旋转
- skewY()——绕着Y轴旋转
- skew()
以上rotate和skew都是需要用到时再去查MDN文档即可。
多重效果可以使用组合来实现:transform:scale(0.5) translate(100%,100%)
;
transform:none
表示取消所有
transition
过渡
作用:补充中间帧
语法: transition:属性名 时长 过渡方式 延迟
- 可以使用,分隔开不同的属性:transition:left 20ms,top 400ms;
- 可以使用all代表所有的属性。
- 过渡方式有很多种:
- linear——线性
- ease——先快后慢
- ease-in
- ease-out
- ease-in-out
- cubic-bezier
- step-start
- step-end
- steps
注意事项:
- 不是所有的属性都可以过渡的。例如:
display:none
=>display:block
就不能过渡。我们一般会改为visibility:hidden
=>visibility:visible
。 - 过渡必须要有起始,一次或者两个动画。
- 如果动画有个中间的点,需要动两次,如何实现?
- 使用两次tranform,先有a使用一次transform到b,再从b使用一次transform到c.
- 使用animation。
animation
语法:
- 声明关键帧
- 添加动画 例如:
- form to
@keyframes slidein{
form{
transform:translate(0%);
}
to{
transform:translate(100%)
}
}
- 百分数
@keyframes identifier{
0%{top:0;left:0;}
30%{top:50px;}
68%,72%{left:50px;}
100%{top:100px;left:100%;}
}
补充:如何让动画停在最后一帧:在animation中加一个forwards。
animation:时长|过渡方式|延迟|次数|方向|填充模式|是否暂停|动画名
- 时长:1s或1000ms
- 过渡方式:跟transition取值一样,如linear
- 次数:3或4或infinite(无限)
- 方向:reverse(从尾到头) | alternate(回返)| alternate-reverse(从尾到头再回返)
- 填充模式:none | forwards(前进) | backwards | both
- 是否暂停:paused(暂停) | running(运行) 以上所有属性都有对应的单独属性,可以在MDN文档中查到。