当前位置: 首页 > Web前端 > HTML

浏览器渲染机制及相应的优化策略

时间:2023-04-03 00:44:45 HTML

浏览器渲染树我们假设在HTTP响应后,HTML、CSS、JavaScript文件都准备好了,此时浏览器会做什么?目前HTTP响应浏览器通用的渲染方式:首先,浏览器根据HTML文件生成DOM树,加载CSS文件构建CSS对象模型。然后,在DOM树和CSSObjectModel上构建渲染树:渲染树就是用来渲染的树。渲染树实际上是DOM树和CSS的结合。与DOM树相同的是,每个HTML标签对应一个渲染树节点。不同的是文本节点比较特殊,每一行文本对应一个渲染树节点。并且,由于渲染树识别CSS,标签和设置为{display:none}的标签不在DOM树上。另外,渲染树上每个节点的样式都已经计算好了。这时候涉及到css选择器的优先级:浏览器默认样式<外部样式表.class>tagName>a:hover,重要的样式有最高优先级。最后,在渲染树建立之后,就可以开始在屏幕上绘制(paint)节点了。重绘和回流当然,这只是第一次绘制,在实践中还会有交互行为,所以页面结构和CSS会随时发生变化,这就涉及到重绘和回流。回流意味着渲染文档的结构已经改变。这时候就需要重新布局了。引起回流的操作包括:DOM元素的删除、表单或文本内容的改变、CSS属性的改变或重新计算、类属性的修改、浏览器窗口的改变(滚动或缩放)、伪类激活。重绘是指当元素的样式变化不影响文档流的整体结构时,渲染树结构没有变化,所以只是重新显示样式。重绘的代价比较小。请注意,这并不是说样式更改不会导致回流,只是特定样式(背景颜色、颜色、可见性)更改不会导致回流。第二点需要注意的是回流一定要重绘,但是重绘不需要回流。发现有些文章没看懂顺序。浏览器优化策略回流和重绘会造成不必要的开销。这是浏览器需要优化的问题之一。罪魁祸首是JavaScript代码执行会改变DOM树和CSS样式,所以通常的做法是缓存JavaScript操作,然后通过回流或重绘一次来解决几次操作的问题。当然,您也可以人为地改变这个浏览器的自主行为。方法是通过获取元素属性强制浏览器立即重绘回流。为什么会这样?假设一个操作需要读取一个元素的高度属性。这时候浏览器已经缓存了几个操作,可能会改变高度值。这时候浏览器要想返回当前的准确值就得马上进行回流。否则,无法获得此准确值。//最终只会触发一次重绘和回流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');另一个优化是浏览器认为一个位置是绝对或固定的元素的变化只会影响它自己和它的子元素,而静态元素的变化会影响到所有后续元素。详见https://segmentfault.com/a/11...,原因是absolute和fixed认为元素从文档流中清除,如何操作是内部的事情。开发优化策略了解浏览器重绘和回流的主要目的是为了优化开发。或许这些开销对于浏览器来说并不重要,但是理解这些会让你对一些优化实践有更深入的理解。例如:批量DOM操作可以通过复制DOM节点,然后对复制的节点进行一系列操作,然后替换原来的节点,因为只要节点没有加入DOM树,渲染树不会受到影响,所以无论你怎么折腾,最后一次加完之后,只会进行一次reflow。这就是“用innerHTML替换DOM操作,减少DOM操作次数,优化javascript性能”的原因。样式计算也是如此。(1)不要一个一个地修改CSS中的样式,每次修改都可能是重绘或者回流,所以最好在原来的CSS中定义不同的类,通过改变类来实现样式转换。(2)只对position为absolute/fixed的元素进行动画处理,因为这些元素不在文档流中,无论怎么移动都不会造成回流,只会重绘。(3)当需要设置的样式较多时,设置className,而不是直接操作样式。(4)避免使用CSSExpression(CSS表达式),也称为动态属性(dynamicproperties)。http://www.phpied.com/renderi...http://taligarsiel.com/Project...