💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 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!')); ```