wcssdu 2019-06-21
我们假设HTTP响应后HTML和CSS、JavaScript文件已经齐备了,此时浏览器会怎么做呢?当前HTTP响应浏览器的普适渲染方式:
首先,浏览器会根据HTML文件生成DOM树,载入CSS文件构建CSS Object Model。然后,在DOM树和CSS Object Model上建立渲染树(render tree):渲染树就是渲染时用到的树。渲染树其实就是DOM树和CSS的组合,和DOM树相同的是每个HTML标签对应一个渲染树节点,不同的是,文本节点比较特殊,每一行文本对应一个渲染树节点,并且,由于渲染树识别CSS,<head>标签以及设置为{display: none}的标签不在DOM树上。除此之外,渲染树上的每个节点该是什么样式也已经计算出来了,此时就涉及CSS选择器的优先级了:浏览器默认样式<外部样式表<style内部样式表,同一样式表内部又有#id > .class > tagName > a:hover,important的样式优先级最高。最后,渲染树建立之后,就可以在屏幕上开始绘制(paint)节点。
当然这仅仅是第一次绘制,实际中会有交互行为,因此页面结构以及CSS会随时变化,这就涉及到重绘(repaint)和回流(reflow)。回流是指渲染文档的结构被改变了,此时要重新布局了,导致回流的操作包括:DOM元素的删改、表单或文本内容变化、CSS属性的更改或重新计算、修改class属性、浏览器窗口变化(滚动或缩放)、伪类激活。重绘是指元素的样式改变不影响文档流整体结构时,渲染树结构也就没有变化,因此仅仅是重新显示样式。重绘的代价是比较小的。注意,这并不是说样式改变不会导致回流,只是特定样式(background-color, color, visibility)改变才不会导致回流。第二个需要注意的点是,回流一定需要重绘,但是重绘却不需要回流,我发现一些文章没搞清顺序。
回流以及重绘会造成不必要的开销,这是浏览器要优化的问题之一,罪魁祸首就是JavaScript代码执行时会改变DOM树和CSS样式,因此常见做法是缓存JavaScript操作,然后通过一次回流或重绘解决几个操作的问题,当然也可以人为改变这一浏览器自主行为,方法就是通过获取元素属性迫使浏览器立即重绘和回流,为什么会这样呢?假设某一操作要读取元素的height属性,此时浏览器已经缓存了几个操作,这些操作可能会改变height值,而此时浏览器要返回当前的精确值,就不得不立即执行回流,否则是得不到这个精确值的。
// 最终只有一次重绘和回流被触发 var $body = $('body'); $body.css('padding', '1px'); // 触发重绘与回流 $body.css('color', 'red'); // 触发重绘 $body.css('margin', '2px'); // 触发重绘与回流 //两次回流 var $body = $('body'); $body.css('padding', '1px'); $body.css('padding'); // 此处触发强制回流 $body.css('color', 'red'); $body.css('margin', '2px');
理解浏览器重绘以及回流的主要目的是为了优化开发,或许这些开销对浏览器不重要,但是了解了这些对一些优化实践就会有更深入的了解。
比如:批量的DOM操作可以通过复制DOM节点,然后在复制的节点上进行一系列操作,再替换原节点即可,因为节点只要不加到DOM树上就不影响渲染树,所以怎么折腾都没事,最后添加之后只执行一次回流。这就是“用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。”的原因。
样式计算也是同样的道理。(1)不要逐个修改CSS中的样式,每次修改可能都是一次重绘或回流,所以最好是在原始CSS里定义不同的class,通过改变class实现样式转换。(2)只对position为absolue/fixed的元素设置动画,因为这些元素不在文档流中,怎么动都不会导致回流,只会重绘。(3)当需要设置的样式很多时设置className而不是直接操作style。(4)避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
http://www.phpied.com/renderi...
http://taligarsiel.com/Projec...
background-color: blue;background-color: yellow;<input type="button" value="变蓝" @click="changeColorT