接着前文看《CSS权威指南》,本文整理一些CSS动画的知识点,同时给出一些例子。
预备知识
变形 Transform
在CSS动画中我们经常需要通过变形来达到一些奇妙的效果。使用 transform 首先要明确变形是基于笛卡尔坐标系,也就是通常所说的 x/y/z
- transform 是基于物体自身的坐标系,百分比也是基于自身的大小
- 移动和旋转的前后顺序很重要,因为物体旋转之后的坐标系也跟着旋转
- 常用函数(live demo):
- 平移函数:
translateX
、translateY
、translateZ
、translate
、translate3d
- 缩放函数:
scaleX
、scaleY
、scaleZ
、scale
、scale3d( number, number, number )
- 旋转函数:
rotateX
、rotateY
、rotateZ
、rotate
、rotate3d( number, number, number, angle)
- 倾斜函数:
skewX
、skewY
、skew
- 视域:
perspective( length )
- 平移函数:
- 重要属性:
transform-origin
、transform-style
、backface-visibility
贝塞尔曲线
在过渡或者动画效果中,我们可能需要使用贝塞尔曲线 cubic-bezier
来控制动画的步调。我们可以在这里 设置不同的曲线并预览,或者在这里 查看一些常用的曲线
动画
属性
animation-name
:指定动画的名称animation-duration
:定义动画的时长(ms | s)animation-iteration-count
:声明动画的迭代次数(number | infinite)animation-direction
:设置动画播放的方向(normal | reverse | alternate | alternate-reverse)animation-delay
:延迟播放动画animation-timing-function
:改变动画的内部时序animation-play-state
:设置动画的播放状态(running | paused)animation-fill-mode
:动画的填充模式,也就是动画结束之后的状态(normal | forwards | backwards | both),最终的显示效果与animation-direction
属性有关
live demo
JS动画事件
animationstart
:动画开始animationiteration
:每次迭代开始animationend
:动画结束
动画延迟效果
给不同对象赋予一定的延迟时间,往往可以形成一些有趣的动画效果。这里我们要区分两种延迟:
- 浏览器把动画附加到元素上之后等待多久开始第一次迭代:
animation-delay: <time>
- 每次迭代开始前需要等待:重复关键帧
live demo/*假设一个小球来回滚动,每次在两边时停留800ms再继续滚动,我们可以由以下动画控制*/ .ball { width: 50px; height: 50px; border-radius: 50%; background-color: orange; animation: move 2000ms infinite alternate;/*alternate 设置来回滚动*/ } @keyframes move { 0%, 40% { transform: translateX(0);/*重复关键帧模拟延迟,2000ms × .4 = 800ms*/ } 60%, 100% { transform: translateX(250px);/*重复关键帧模拟延迟,2000ms × .4 = 800ms*/ } } 复制代码
从中间帧开始执行动画
如果animation-delay
的值为负,而且绝对值比animation-duration
小,那么动画将立即开始并且从中间的关键帧开始播放。例如,一个动画时长为 10s
,延迟时间为 -4s
,那么如果 animation-timing-function
为 linear
,则将从动画的 40%
开始播放
利用 box-shadow
利用 box-shadow 可以创建为单个元素创建多个 border。例如,我们可以利用这个属性为一个 loading 动画添加多个小的圆圈。
// 我们通过变换box-shadow来交换正方形的位置
.spinner {
position: absolute;
/*border-radius: 50%; need width > 0 and height > 0*/
width: 0;
height: 0;
box-shadow:
-30px -30px 0 40px #a593e0,
-30px 30px 0 40px #e0e3da,
30px 30px 0 40px #fffff3,
30px -30px 0 40px #566270;
animation: spin 3000ms infinite alternate;
}
复制代码
利用伪元素
我们注意到利用 box-shadow 属性,所有“子元素”是绑定在“父元素”上且同时变化的。如果我们不想引入多余的 DOM 元素,同时又想“子元素”不与“父元素”同时进行变换,我们可以采用::after
和::before
来创建。
来看一些有趣的例子吧
动画性能
讲完了一些基础知识,让我们进一步聊聊动画渲染的性能。
浏览器底层原理
浏览器的工作原理,请看 How Browsers Work: Behind the scenes of modern web browsers,写的很详尽,值得一读。
浏览器处理的过程很简单:计算元素的样式(重新计算样式),生成每个元素的几何形状和位置(布局),绘制图层中的每个像素(初始化绘图并且进行绘图)并且将图层绘制到屏幕上(图层的合成)浏览器内部
现代浏览器通常有两个主要的线程:① main thread;② compositor thread
- 主线程的主要职责是(维持一个RenderLayers):
- 运行脚本
- 计算 HTML 元素的 CSS 属性
- 页面布局
- 把 DOM 元素绘制到一个或者多个位图上
- 把合成的位图交给compositor thread
- 合成线程的主要职责是(维持一个 GraphicsLayers):
- 通过 GPU 把位图绘制到屏幕上
- 请求主线程更新呈现在屏幕上或者即将呈现在屏幕上的位图
- 当进行滚动操作时,弄清楚哪部分即将呈现在屏幕上
- 当进行滚动的时候,移动相应部分的页面
合成线程会尽可能响应用户的鼠标键盘等消息事件。可能发生的情况是,当页面滚动需要更新视图时,合成线程以每帧(60fps)请求更新位图(刷新屏幕),但主线程上可能正进行复杂的脚本运算或者HTML元素绘制,导致合成线程无法及时拿到位图,这时合成线程会绘制空白。
GPU
GPU 能够很快地处理将位图绘制到屏幕上的操作,还能很快处理将同一位图通过变换再次绘制的操作,但是对于从内存中加载位图的处理比较慢。比较一个过渡效果使用 height 和 transform 的两个流程:
composited layer 创建的条件
- 使用视频加速解码的 video 元素
- flash、使用3D (WebGL) context 的 canvas 元素
- CSS transform
- CSS filter
- CSS opacity
高性能的 CSS动画
减少消耗成本
为什么有些动画播放流畅,有些则显得很卡顿呢?从上面的知识中,我们或许会得到一些启发:现代浏览器在完成 position(位置), scale(比例缩放), rotation(旋转) 和 opacity(透明度)这四种属性的动画时,消耗成本较低。
如果我们使用 height 进行变换,浏览器可能在每帧需要请求主线程重新布局、绘制和更新位图,再将位图从 CPU 传给 GPU,这个过程可能导致卡顿,也就是我们丢失了某些关键帧。
但是使用 height 的性能就一定比 transform 的性能差?不一定,可能的情况是:① 绘制的位图很小;② height 更新不会影响其他元素的布局等情况;③ 元素是脱离正常流的;
我们在使用 width、display、font-size、box-shadow、color 等可能引起重排或者重绘的属性时,如果你不能清楚的知道自己在做什么,我们还是建议使用推荐的操作避免糟糕的情况出现。
JS动画和CSS动画的优缺点
- 优点:JavaScript中的动画可以为你提供更多的控制,比如开始,暂停,回放,中断和取消等,还可以进行设计复杂的动画效果。缺点:主线程上可能进行复杂的运算,增大掉帧的风险(我们也可以放在 Web Worker 中进行)。
- 优点:浏览器会对CSS动画进行优化,如果有需要,它会创建图层,并且可以在主进程之外完成一些操作。缺点就是CSS动画相对于Javascript动画而言,缺乏表现力,对动画的设计来说更加复杂。
参考博客及推荐阅读
- Animatable CSS properties
- CSS Triggers
- CSS animations and transitions performance: looking inside the browser
- Accelerated Rendering in Chrome
- High Performance Animations
- CSS animations and transitions performance: looking inside the browser
- Starting CSS Animations Mid-Way
- Animating with Clip-Path
- How Browsers Work: Behind the scenes of modern web browsers
- 网页性能管理详解