动画:
由许多静止的画面(帧),以一定的速度(如每秒30张)连续播放时,肉眼因视觉残象产生错觉,而误以为是活动的画面。
概念:
帧:每个静止的画面都叫帧。
例:
HTML:
<body>
<div id="demo"></div>
</body>
CSS:
#demo{
width:100px;
height:100px;
border:1px solid red;
position: relative;
left:0;
}
JS:
var n = 1
var id = setInterval(()=>{
if(n <= 200){
demo.style.left = n + 'px'
n = n+1
}else{
console.log('1')
clearInterval(id)
}
},1000/60)
var id = ....
clearInterval(id)
做计时器,必须这样写,才能防止报错,必须给个id,然后clearInterval(id)
- 原理: 每过一段时间【用setInterval(设置间隔) 做到】将div移动一小段距离,直到移动到目标地点。
在开发者工具界面的任何一个标签,按ESC出现一个rendering(┆选中即可),勾选paint flashing
渲染: 就是把某个区域重新画一下,绿色区域闪烁可以理解为擦掉重画。
- 注意性能
绿色表示重新绘制(repaint),CSS渲染过程依次包含布局、绘制、合成。
其中布局和绘制有可能被省略。
前端高手不用left做动画,用transform(变形)
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="demo"></div>
</body>
</html>
CSS:
#demo{
width: 100px;
height: 100px;
border:1px solid red;
transition: all 1s linear;
}
#demo.end{
transform: translateX(200px);
}
JS:
setTimeout(()=>{
demo.classList.add('end')
},5000) //5000是5秒的意思
- 原理: transform:translateX(0 => 300px)
直接修改会被合成,需要等一会修改。
transtion过渡属性可以自动脑补中间帧。
- 注意性能 并没有repaint(重新绘制),比改left性能好
浏览器渲染过程
步骤:
- 根据HTML构建HTML树(DOM)
- 根据CSS构建CSS树(CSSOM)
- 将两棵树合并成一颗渲染树(render tree)
- Layout布局(文档流、盒模型、机算大小和位置)
- Paint绘制(把边框颜色、文字颜色、阴影等画出来)
- Composite合成(根据层叠关系展示画面)
如何更新样式?
一般用JS来更新样式
比如 div.style.background = 'red'
比如 div.style.display = 'none'
比如 div.classList.add('red')
比如 div.remove()
直接删掉节点
三种不同的更新渲染方式
-
JS/CSS > 样式 > 布局 > 绘制 > 合成
-
JS/CSS > 样式 > 绘制 > 合成
-
JS/CSS > 样式 > 合成
-
第一种,全走 demo.remove( )会触发当前消失,其他元素 relayout (重新布局)
-
第二种,跳过layout
改变背景颜色 ,直接repaint + composite
- 第三种,跳过layout和paint 改变transform 只需composite 注意必须全屏看效果,在iframe里面看效果
查看每个属性触发什么流程,上 csstrigger.com
CSS动画优化
JS优化:
使用requstAnimationFrame代替,setTimeout或者setInterval。
CSS优化:
使用will-change或translate
transform全解
- 四个常用功能
- 位移translate
- 缩放scale
- 旋转rotate
- 倾斜skew
- 经验
- 一般都需要配合transition过渡
- inline元素不支持transform,需要很变成block
:hover定义:鼠标移动元素上时添加样式
transfor之translate
- 常用写法
1. translateX(<length - percentage>) //length: 长度
2. translateY(<length - percentage>) //percentage: 百分数
<length - percentage>表示可以跟一个长度 (比如20px) 或者 百分数(50%)
3. translate(<length - percentage> , <length - percentage>?) //?表示可省略
例:
transform = translateX(50%) , 表示往右移动当前身位(宽度)的50%
transform = translateX(-50%) , 表示往左移动当前身位(宽度)的50%
transform = translateY(50%)则向下移动50% , -50%则向上
transform = transformZ(<length>)
且要在父容器上加perspective 例:
HTML:
<div class = "wrapper">
<div id = "demo"></div>
</div>
CSS:
#demo: hover{
transform: translateZ(-200px);
}
.wrapper{
perspective: 1000px;
border: 1px solid red;
}
5. translate3d(x,y,z)
- 经验 1. 学会看懂MDN的语法示例
2. translate(-50% , -50%)可做绝对定位的居中
绝对定位居中,代码示例:
#demo{
width: 100px;
height: 100px;
border: 1px solid red;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50% , -50%);
}
.wrapper{
border: 1px solid red;
position: relative;
min-height: 500px;
}
transform之scale
常用写法:
ScaleX(<number>)
X方向上(横向)缩放,大于1放大,小于1缩小,0消失
ScaleY(<number>)
Y方向上(纵向)缩放,大于1放大,大于1缩小,0消失
Scale(<number>,<number>?)
X、Y轴缩放同时进行
例:transform: scale(1.5);
经验:用得较少,因为容易出现模糊。
transform之rotate
常用写法:
rotate([<angle> | <zero>]) //默认不写Z , angle: 角度 , |: 或 , zero: 零
例:transform: rotate(45deg); //角度的单位是deg , degree缩写
rotateZ([<angle> | <zero>]) //Z轴旋转
rotateX([<angle> | <zero>]) //X轴旋转
rotateY([<angle> | <zero>]) //Y轴旋转
transition: all 1s/0.5s/.5s;
transition(过渡;转变)不能放在:hover里,不然会丢失后半部分的动画
transition用于加动画效果,意思是1秒内完成动画,一般和transform联用
0.5s可以简写成.5s
rotate3d太复杂,用的时候再学
- 经验: 一般用于360度旋转制作loading,用到时再看MDN
transform之skew
常用写法:
skewX([<angle> | <zero>])
例:transform: skew(45deg); (deg角度单位)
skewY([<angle> | <zero>])
skew([<angle> | <zero>] , [<angle> | <zero>]?)
transform多重效果
组合使用
transform: scale(0.5) translate(-100% , -100%);
transform: none; //取消所有
transform: scale(1.5) rotate(45deg); //缩放后再旋转
可以自由组合,记得用空格隔开
border-radius: 50% 50% 50% 50%;
4个50%分别对应4个角,50%就是变圆,用来给边框border变圆
transition(过渡)
作用:补充中间帧
语法: transition:属性名 时长 过渡方式 延迟
例: transtion:left 200ms linear 300ms;
可以用逗号分隔两个不同的属性。
例:transition:left 200ms,top 400ms;
可以用all代表所有属性
例:transition: all 200ms;
过渡方式有:linear | ease | ease-in | ease-out | ease-inout | cubic-bezier | step-start | step-end | steps
具体含义要靠数学知识,不懂找MDN搜timing-function
- 注意!
并不是所有属性都能过渡
display: block————none没法过渡
none————block也不行
让一个东西从看得见到看不见可以用opacity,但它有一个bug,就是消失以后还会占着一个原来的空间,因为知识控制透明度,位置还占着。需要在结束取消掉,一般不用。
一般改成visibility: visible————visibility: hidden;
但也会保留原来的位置空间
background颜色也可以过渡,比如,background: red——white
过渡必须要有起始,一般只有一次动画,或者两次
比如,hover和非hover状态的过渡
如果除了起始,还有中间点,怎么办?
两种方法:
1. 使用两次transform
·a————transform—————·b
·b————transform—————·c
如何知道到了中间点呢?
用setTimeout或者监听transitionend事件
例:
HTML:
<div class="wrapper">
<div id="demo"></div>
<button id=button>开始</button>
</div>
CSS:
#demo{
width:100px;
height:100px;
border:1px solid red;
margin:50px;
transition:transform 1s linear;
}
#demo.b{
transform:translateX(200px);
}
#demo.c{
transform:translateX(200px) translateY(100px); //translateX(200px)不加的话会偏移,忘了打一遍就会了
}
JS:
button.onclick=()=>{
demo.classList.add('b')
setTimeout(()=>{
demo.classList.remove('b')
demo.classList.add('c')
},1000)
}
2. 使用animation
- 步骤:
- 声明关键帧
- 添加动画 例:
HTML:
<div class="wrapper">
<div id="demo"></div>
<button id=button>开始</button>
</div>
CSS:
#demo{
width:100px;
height:100px;
border:1px solid red;
margin:50px;
transition:transform 1s linear;
}
#demo.start{
animation:xxx 1.5s;
}
@keyframes xxx{
0%{
transform:none;
}
66.66%{
transform:translateX(200px);
}
100%{
transform:translateX(200px) translateY(100px);}
}
JS:
button.onclick =()=>{
demo.classList.add('start')
}
如何让动画停在最后一帧?
搜CSS animation stop at end
答案是加个forwards
在animation: xxx 1.5s forwards;
就停在最后一帧了
@keyframes完整语法
- 一种是from to
例如:
@keyframes slidein{
from{
transform:translateX(0%);
}
to{
transform:translateX(100%);
}
}
- 另一种是百分数
@keyframes xxx{
0%{..........;}
30%{.........;}
68%,72%{.........;}
100%{............;}
}
animation
animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名;
-
时长: 1s或1000ms
-
过渡方式:跟transition 取值一样,如 linear,ease
-
次数:3或者2.4,数字或小数都可以,再或者infinite(无限)
-
方向:reverse | alternate | alternate-reverse
-
填充模式:none | forwards | backwards | both
-
是否暂停:paused | running
以上所有属性都有对应的单独属性
暂停功能,代码示例:
<button id=xxx>暂停</button>
JS:xxx.onclick=()=>{
demo.style.animationPlayState='paused' | running(运行)
}
不懂去看MDN文档,然后实践敲一遍