## CSS解析,构建CSSOM
### 生成CSS规则
同理,CSS规则树的生成也是类似。简述为:
```
Bytes → characters → tokens → nodes → CSSOM
```
譬如`style.css`内容如下:
```
body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }
```
那么最终的CSSOM树就是:
![img](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/date/2018-03-29/browser_parse_cssom.png)
### 构建渲染树
当DOM树和CSSOM都有了后,就要开始构建渲染树了
一般来说,渲染树和DOM树相对应的,但不是严格意义上的一一对应
因为有一些不可见的DOM元素不会插入到渲染树中,如head这种不可见的标签或者`display: none`等
整体来说可以看图:
![img](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/date/2018-03-29/browser_parse_rendertree.png)
### 渲染
有了render树,接下来就是开始渲染,基本流程如下:
![img](http://xiaoyulive.oss-cn-beijing.aliyuncs.com/date/2018-03-29/browser_rendingprocess.jpg)
图中重要的四个步骤就是:
```
1. 计算CSS样式
2. 构建渲染树
3. 布局,主要定位坐标和大小,是否换行,各种position overflow z-index属性
4. 绘制,将图像绘制出来
```
然后,图中的线与箭头代表通过js动态修改了DOM或CSS,导致了重新布局(Layout)或渲染(Repaint)
这里Layout和Repaint的概念是有区别的:
- Layout,也称为Reflow,即回流。一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树
- Repaint,即重绘。意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就可以了
回流的成本开销要高于重绘,而且一个节点的回流往往回导致子节点以及同级节点的回流, 所以优化方案中一般都包括,尽量避免回流。
**什么会引起回流?**
1. 页面渲染初始化
2. DOM结构改变,比如删除了某个节点
3. render树变化,比如减少了padding
4. 窗口resize
5. 最复杂的一种:获取某些属性,引发回流,
很多浏览器会对回流做优化,会等到数量足够时做一次批处理回流,
但是除了render树的直接变化,当获取一些属性时,浏览器为了获得正确的值也会触发回流,这样使得浏览器优化无效,包括
(1)offset(Top/Left/Width/Height)
(2) scroll(Top/Left/Width/Height)
(3) cilent(Top/Left/Width/Height)
(4) width, height
(5) 调用了getComputedStyle()或者IE的currentStyle
**回流一定伴随着重绘,重绘却可以单独出现**
所以一般会有一些优化方案,如:
- 减少逐项更改样式,最好一次性更改style,或者将样式定义为class并一次性更新
- 避免循环操作dom,创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document
- 避免多次读取offset等属性。无法避免则将它们缓存到变量
- 将复杂的元素绝对定位或固定定位,使得它脱离文档流,否则回流代价会很高
**注意:改变字体大小会引发回流**
再来看一个示例:
```js
var s = document.body.style;
s.padding = "2px"; // 回流+重绘
s.border = "1px solid red"; // 回流+重绘
s.color = "blue"; // 重绘
s.backgroundColor = "#ccc"; // 重绘
s.fontSize = "14px"; // 回流+重绘
// 添加node 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));
```
- Web 开发笔记
- 从输入 URL 到页面加载完成的过程中都发生了什么事情?
- 从浏览器接收url到开启网络请求线程
- 开启网络线程到发出一个完整的http请求
- 从服务器接收到请求到对应后台接收到请求
- 后台和前台的http交互
- http的缓存
- 解析页面流程
- HTML解析,构建DOM
- CSS解析,构建CSSOM
- 资源外链的下载
- CSS的可视化格式模型
- 包含块(Containing Block)
- 控制框(Controlling Box)
- BFC(Block Formatting Context)
- IFC(Inline Formatting Context)
- 其它
- JS引擎解析过程
- JS的解释阶段
- JS的预处理阶段
- JS的执行阶段
- 回收机制
- 参考资料
- JavaScript模块化编程
- AMD
- requireJS
- CommonJS
- UMD
- ES6模块
- 参考资料
- 使用 JavaScript 实现一门编程语言
- 如何使用 JavaScript 实现一门编程语言(1) —— 前言
- 如何使用 JavaScript 实现一门编程语言(2) —— 编写一个解析器
- 如何使用 JavaScript 实现一门编程语言(3) —— Input stream
- 如何使用 JavaScript 实现一门编程语言(4) —— Token stream
- 如何使用 JavaScript 实现一门编程语言(5) —— AST
- 如何使用 JavaScript 实现一门编程语言(6) —— Interpreter
- 完整代码
- 参考资料
- 前端布局概论
- 参考资料
- Windows 笔记
- 错误解决
- win10应用商店无法登录提示0x80070426解决方法
- 使用技巧
- 设置 Hyper-V 和 VMware 共存
- Powershell
- WSL