动画
- 定义:由许多静止的画面(帧),以一定的速度(如每秒30张)连续播放时,肉眼因视觉残象产生错觉,而误以为是活动的画面
- 概念
- 帧:每个静止的画面都叫做帧。
- 播放速度:每秒24帧(影视)或者每秒30帧(游戏)。
一个简易动画
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<style>
#demo {
width: 100px;
height: 100px;
border: 1px solid red;
position: relative;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="demo"></div>
<script>
let n = 1;
let id = setInterval(()=>{
if(n <= 200) {
demo.style.left = `${n}px`;
n++
}else{
clearInterval(id);
}
},10)
</script>
</body>
</html>
- 原理
- 每过一段时间(用setInterval)
- 将div移动一小段距离(元素.style.left)
- 知道移动到目标地点(用if来判断是否移动到正确位置)
浏览器的渲染原理
浏览器的渲染
- 步骤
- 根据HTML构建HTML树(DOM)
- 根据CSS构建CSS树(CSSOM)
- 将两棵树合并成一颗渲染树(render tree)
- Layout布局(文档流、 盒模型、计算大小和位置)
- Paint绘制(把边框颜色、文字颜色、阴影等画出来)
- Compose合成(根据层叠关系展示画面)
- Chrome的Paint flashing功能
- 控制台→Esc键→Rendering→Paint flashing
- 绿色表示正在重新渲染(repaint)。
- CSS渲染过程依次包含布局、绘制、合成, 其中布局和绘制可能被省略。
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<style>
#demo {
width: 100px;
height: 100px;
border: 1px red solid;
transition: all 1s linear;
}
#demo.end {
transform: translateX(300px);
}
</style>
</head>
<body>
<div id="demo"></div>
<script>
setTimeout(()=>{
demo.classList.add('end')
},3000)
</script>
</body>
</html>
- 使用transform来实现动画,要比left实现动画所渲染的要少,对资源占用更少,因此一般不用left来做动画。
- 一般用JS来更新样式
div.style.background= 'red';不推荐
div.style.display = 'none';
div.classList. add('red');推荐
div.remove();直接删掉节点
- 加样式不如加类。
三种样式的更新方式
- JS/CSS→样式→布局→绘制→合成
- JS/CSS→样式→绘制→合成
- JS/CSS→样式→合成
如何了解某个属性触发什么动画流程
CSS动画优化
- 作用:旋转、缩放、倾斜或平移给定元素。
- Google写的CSS动画文章
- JS优化:使用requestAnimationFrame替代setTimeout或setInterval。
- CSS优化:使用will-change或translate替代left等。
transfrom属性
- MDN transform文档
- 常用功能
- translate:位移
- scale:缩放
- rotate:旋转
- skew:倾斜
- 注意
- 一般都需要配合transition过度。
- inline元素不支持transform,需要先变成block。
transform: translate()
- 常用属性值
translateX(<length-percentage>):X轴方向(水平)上移动。
translateY(<length-percentage>):Y轴方向(垂直)上移动。
translateZ(<length-percentage>):Z轴方向上移动,需要配合父元素的perspective属性,改变视点。
translate(<length-percentage>, <length-percentage>):(X轴方向, Y轴方向)。
translate3d(<length-percentage>, <length-percentage>, <length-percentage>):(X轴方向, Y轴方向, Z轴方向)。
- 注意
transform: scale()
- 常用属性值
scaleX(<number>):X轴方向上放大(缩小)多少倍。
scaleY(<number>):Y轴方向上放大(缩小)多少倍。
scale(<number>):整体放大(缩小)多少倍。
scale(<number>, <number>):(X轴方向,Y轴方向)放大(缩小)多少倍。
- 注意
- 一般不用scale,因为会拉伸元素,导致变形、出现模糊。
transform: rotate()
- 常用属性值
- 注意
- <angle>的单位是deg,degree的缩写。
- 默认为顺时针旋转。
- 一般用360度旋转制作loading。
transform: skew()
- 常用属性值
skewX(<angle>):沿着X轴方向旋转拉伸。
skewY(<angle>):沿着Y轴方向旋转拉伸。
transform多重效果
- 组合使用:
transform: scale(0.5) translate(100%, 100%);
- 取消所有:
transform: none;
transition属性
- 作用:补充中间帧。
- 语法:
transition: 属性名 时长 过度方式 延迟;
- 例:
transition: left 200ms linear 400ms;
- 可用逗号分隔两个不同属性。
- 例:
transition: let 200ms, top 400ms;
- 可以用all代表所有属性。
- 过度方式:linear(线性变化)、ease(非线性变化)、ease-in、ease-out、ease-in-out、cubic-bezier、step-start、step-end、steps
- 注意
- 并不是所有属性都能使用transition属性。
display: none→display: block没法过渡,一般改成visibility: hidden;→visibility: visible;。
- color、background-color、opacity也可以transition。
- 基本上只要变化过程有规律的都可以transition。
- 可以用事件监听和两个transform来实现连续的两次transition。
animation
obj.start {
animation: slidein 1.5s;
}
@keyframes slidein {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(100%);
}
}
- animation语法:
animation: 时长 过度方式 延迟 次数 方向 填充模式 是否暂停 动画名;
- 时长:1s或者1000ms
- 过渡方式:跟transition取值一样,如linear、ease
- 次数:3或者2.4或者infinite
- 方向:reverse | alternate| alternate-reverse
- 填充模式:none | forwards | backwards | both
- 是否暂停:paused | running
- 以上所有属性都有对应的单独属性
- @keyframes:关键帧,另一种写法是from to格式。
- keyframes MDN
- 如何使动画停在最后一帧?
- 为animation添加一个forwards,如
animation: slidein 1.5s forwards;
拓展
opacity、display、visibility的区别
opacity: 0;只是改变元素的透明度,但还会占用布局空间。会一边改变透明度,一边执行过渡动画。
visibility: hidden;只是改变元素的透明度,但还会占用布局空间。会先执行动画,再改变透明度。
display: none;会改变元素的透明度,但不会占用空间。