CSS 动画知识总结
一个简单的例子
使用 left 将 div 从左往右移动
原理
每过一段时间(用 setInterval 做到)将 div 移动一小段距离,直到移动到目标地点
注意性能
开发者页面按 ESC调出控制台,点击三个点选择 Rendering,在 Rendering 页面勾选 Paint flashing。勾选完毕后页面上的绿色表示重新绘制 (repaint)。
CSS 渲染过程一次包含布局、绘制、合成。其中布局和绘制有可能被省略。
改进 使用 transform 将 div 从左往右移动
原理
transform: translateX(300px)
直接修改会被合成,需要等一会修改。使用 transition 过渡属性可以自动脑补中间帧。
性能
并没有重新绘制(repaint),比改 left 性能好。
浏览器渲染原理
参考文章
Google 团队
查看 CSS 各属性触发什么
浏览器渲染步骤
- 根据 HTML 构建 HTML 树 (DOM)
- 根据 CSS 构建 CSS 树 (CSSOM)
- 将两棵树合并成一颗渲染树 (Render Tree)
- Layout 布局 (文档流、盒模型、计算大小和位置)
- Paint 绘制(把边框颜色、文字颜色、阴影等画出来)
- Compose 合成 (根据层叠关系展示画面)
使用 JS 更新样式
比如div.style.background = 'red'
, div.style.display = 'none'
, div.classList.add('red')
, div.remove()
一般常用的是加类的方式,更方便。
三种更新样式的方式
-
JS/CSS > Style > Layout > Paint > Composite
经历全部步骤。 比如 div.remove() 会触发当前元素消失,其他元素重新布局
-
JS/CSS > Style > Paint > Composite
跳过 layout,直接 paint + composite。比如说改变背景颜色
-
JS/CSS > Style > Composite
跳过 layout 和 paint,只需 composite。(必须全屏查看效果,在 iframe 里看会有问题)。比如说改变 transform
可以在 https://csstriggers.com/ 中查阅各属性触发什么流程
CSS 动画优化
具体查询 Google 文档,需要记住的有
-
JS 优化
使用 requestAnimationFrame 代替 setTimeout / setInterval
-
CSS 优化
使用 will-change / translate
transform
经验
- 一般都会配合 transition 过渡
- inline 元素不支持 transform, 需要先变成 block
translate
X 是横轴,Y 是纵轴,Z 是屏幕向里的方向
常用语法
-
translateX(<length-percentage>)
length 表示具体像素值,pecentage 表示元素长度的百分比,两者皆可使用
translateY(<length-percentage>)
-
translate(<length-percentage>, <length-percentage>?)
先 X 后 Y
-
translateZ(<length>)
且父元素要设置 perspectiveperspective:1000px
表示视点位于视窗正中心 Z 轴方向上 1000px 远的地方 translate3d(x,y,z)
经验
translate(-50%, -50%)
可做绝对定位元素的居中。
scale
常用语法
scaleX(<number>)
scaleY(<number>)
scale(<number>,<number>?)
经验
较少使用,图片容易出现模糊
rotate
常用语法
-
rotate([<angle> | <zero>])
angle 单位是 deg | grad | rad | turn。默认是绕 Z 轴旋转
rotateZ([<angle> | <zero>])
rotateX([<angle> | <zero>])
rotateY([<angle> | <zero>])
rotate3d([<number> |<number> |<number> |<angle>])
经验
一般用于 360deg 旋转制作 loading
skew
常用写法
skewX([<angle> | <zero>])
skewY([<angle> | <zero>])
skew([<angle> | <zero>],[<angle> | <zero>]?)
多重效果
中间用空格隔开即可
transform: scale(0.5) translate(-100%, -100%);
取消所有
transform:none;
使用 transform: rotate
旋转后坐标轴也会旋转
实践
使用 transform 和 transition 实现跳动的心。
实践时发现 transform 中的 rotate 是以长方形右下角的定点为轴进行旋转
transition 过渡
作用
补充中间帧
语法
-
transition 属性名 时长 过渡方式 延迟
transition: left 200ms linear
过渡方式有 linear |ease | ease-in | ease-out | ease-in-out | cubic-bezier | step-start | step-end | steps
-
可以用逗号分割两个不同属性
transition: left 200ms, top 400ms
-
可以用 all 代表所有属性
transition: all 200ms
注意
并不是所有属性都有过渡
-
display: none => block 无法过渡
display: none 即元素不可见,且不为其保留相应位置
-
visibility: hidden => visible 可以过渡
visibility: hidden 即元素不可见但保留相应位置
-
background, opacity 可以过渡
我感觉属性值可以连续变化的都可以过渡
-
过渡必须要有起始点
一般只有一次动画,hover 和 非 hover 时有两次
包括起始点与中间点的过渡
使用两次 transform
- 用 SetTimeoout 或者监听 transitioned 来确认到了中间点,此时移除类 .b,增加类 .c
如果 .c 要延续 .b 的状态运动,一般 .c 中要包括 .b 的内容
使用 animation
- 声明关键帧
- 添加动画
animation
@keyframes 语法
详见 MDN文档
from to 写法
@keyframes eg1{
from {
transform: translateX(0%);
}
to {
transform: translateX(100%)
}
}
百分数写法
@keyframes eg2{
0% {top: 0; left:0;}
30% {top: 50px;}
60%, 70% {left: 50px;}
100% {top: 100px; left:100%;}
}
animation 缩写语法
animation: 时长 duration| 过渡方式 timing-function| 延迟 delay| 次数 iteration-count| 方向 direction| 填充模式 fill-mode| 是否暂停 play-state| 动画名 name;
animation: duration | timing-function | delay | name
animation: duartion | name
时长 1s or 1000ms
过渡方式 linear |ease | ease-in | ease-out | ease-in-out | cubic-bezier | step-start | step-end | steps
次数 3 or 2.6 or infinite
方向 reverse | alternate | alternate-reverse
-
填充模式 none | forwards | backwards | both
需要动画停在最后一帧时使用 forwards. 演示
-
是否暂停 paused | running
可以通过添加按键,在 JS 根据按键是否按下来改变 animationPlayState 的状态
动画名放哪里都可以
以上属性都有对应的单独属性