1. 浏览器渲染
1.1 浏览器渲染的步骤
浏览器渲染流程大致分为以下几个步骤:
- 根据 HTML 构建 HTML 树(DOM);
- 根据 CSS 构建 CSS 树(CSSOM);
- 将两棵树合并成一棵渲染树(render tree);
- Layout 布局(文档流、盒模型、计算大小和位置);
- Paint 绘制(把边框颜色,文字颜色阴影等画出来);
- Composite 合成(根据层叠关系展示画面)。
1.2 更新 CSS 样式的方法和步骤
一般用 JavaScript 更新样式,可以修改样式或者添加类,添加类更为方便常用。使用 JavaScript 更新样式要经过布局、绘制、合成这几个步骤中的一步、二步或者全部。
- 经过布局、绘制、合成全部过程,如删除某 div 元素;
- 经过绘制、合成过程,如改变某元素背景颜色,因为位置、大小未改变,不影响布局;
- 经过合成过程,如改变 transform 属性,在 Chrome 浏览器只需要合成。
1.3 各属性触发相应流程的查询方式
通过 csstriggers.com 查询各属性改变时在各浏览器触发了哪些的流程。
各主要浏览器内核标识如下:
- Blink:Chrome 浏览器
- Geckko:Firefox 浏览器
- Webkit:Safari 浏览器
- EdgeHTML:IE 最新版
1.4 浏览器渲染与 CSS 动画优化的关系
打开 Chrome 开发者工具,按 ESC,点击 Rendering,勾选 Paint flashing,此时页面会出现绿色部分闪烁,绿色闪烁代表重新渲染,就相当于在屏幕上这块区域重新画一下。
通过 JavaScript 定时器设置每秒移动固定位移实现的动画,对应元素一直在重新渲染。而通过设置 transform 实现的动画,在 Chrome 浏览器测试,元素只在起始位置渲染,优化了 CSS 性能。
CSS 动画优化经常采用以下方式
- JS 优化:使用 requestAnimationFrame 代替 setTimeout 或 setInterval;
- CSS 优化:使用 will-change 或 transform。
2. CSS 动画
每个静止的画面都是帧,连续的帧形成了动画。影视通常每秒 24 帧,游戏每秒 30 帧以上,有追求画面的游戏达到 120 ~ 140 帧甚至更高。
2.1 transform 变形
四个常用功能:
- 位移 translate
- 缩放 scale
- 旋转 rotate
- 倾斜 skew
transform 一般需要配合 transition 使用。inline-block 元素不支持 transform,需要先变成 block。
针对 translateZ 的移动,需要设置 perspective(透视原点位置)才能观察到效果。如 perspective: 1000px,即透视原点位于距元素正中心 1000px 远处。
/* 通过 transform 实现绝对定位元素居中,不支持 IE */
.demo {
width: 200px;
height: 200px;
border: 1px solid red;
position: absolute;
left: 50%;
top: 50%;
/* 回半个身位 */
/* transform: translateX(-50%) translateY(-50%);*/
transform: translate(-50%, -50%);
}
2.2 transition 过渡
- 作用:补充中间帧
- 语法: transition: 属性名 时长 过渡方式 延迟时间
可拆分设置 transition-property: width,background,transition-duration: 2s,10s。
可自定义贝塞尔曲线 cubic-bezier(0, 0.95, 1, 0.07)
延迟时间 transition-delay: 3s;
所有属性同样过渡 transition: all 2s;
- 过渡方式:linear(线性) | ease(缓动)| ease in(缓入,从慢到快)| ease out(缓出,从快到慢)| ease-in-out(缓入缓出)| ...
- display:none --> block 没办法过渡,一般改为 visibility:hidden --> visible
- visibility: hidden 仍然占用域的空间
- 过渡必须要有起始
2.3 animation 动画
声明关键帧,添加动画。@keyframes 两种写法。
.demo.strat {
animation: moveExample 1s;
}
/* 写法一 */
@keyframes moveExample {
from {
transform: translateX(0%);
}
to {
transform: translateX(100%);
}
}
/* 写法二 */
@keyframes moveExample {
0% {
transform: translateX(0%);
}
30% {
transform: rotate(45deg);
}
60%, 70% {
transform: scale(1.2);
}
100% {
transform: translateX(100%);
}
}
animation 简写
- animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充方式 | 是否暂停 | 动画名
- animation-name: moveExample —— 动画名称
- animation-duration: 3s —— 动画时间周期
- animation-timing-function: ease —— 动画速度曲线
- animation-delay: 1s —— 动画延迟时间
- animation-iteration-count: 3(3次) | infinite(无限次)—— 动画循环次数
- animation-direction: normal —— 运动的方向。
alternate交替运动(奇数次正常运动,偶数次反向),reverse 反向运动,alternate-reverse 奇数次反向偶数次正向运动。
- animation-fill-mode: fowards; —— 使得动画保留最后一帧的效果
3. 小案例
- 使用 transform、transition 和 :hover 实现会动的红心
* {
padding: 0;
margin: 0;
}
.wrap {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
#heart {
position: relative;
transition: all 1s;
}
#heart:hover {
transform: scale(1.2);
transition: all 1s;
}
.left {
position: absolute;
bottom: 100%;
right: 100%;
width: 200px;
height: 200px;
background: red;
border-radius: 50% 0 0 50%;
transform: rotate(45deg) translateX(170px);
}
.right {
position: absolute;
bottom: 100%;
left: 100%;
width: 200px;
height: 200px;
background: red;
border-radius: 50% 50% 0 0;
transform: rotate(45deg) translateY(170px);
}
.bottom {
width: 200px;
height: 200px;
background: red;
transform: rotate(45deg);
}
<body>
<div class="wrap">
<div id="heart">
<div class="left"></div>
<div class="right"></div>
<div class="bottom"></div>
</div>
</div>
</body>
- 使用 animation 实现会动的红心。
#heart {
position: relative;
animation: heart 0.7s ease infinite alternate;
}
@keyframes heart {
0% {
transform: scale(1);
}
100% {
transform: scale(1.2);
}
}