其实关于网页渲染的文章很多,但是相关资料??比较零散,讨论的不是很完整。如果我们要对这个主题有一个大概的了解,还有很多东西要学。因此,Web开发人员AlexanderSkutin决定写一篇文章。他认为这篇文章不仅可以帮助初学者,也可以让想要刷新知识结构的高级前端开发者受益。译文如下:网页渲染必须在很早的阶段进行,早在页面布局刚刚完成时。因为样式和脚本对网页渲染都有着至关重要的影响。因此,专业的开发人员必须了解一些技巧,以避免在实践中遇到性能问题。本文不会深入研究浏览器内部的详细机制,而是提出一些通用规则。毕竟不同的浏览器引擎工作方式不同,这无疑会增加开发者对浏览器特性的研究。浏览器是如何完成网页渲染的?首先,让我们回顾一下浏览器在渲染网页时的动作:根据来自服务器的HTML代码形成文档对象模型(DOM),加载和解析样式,形成CSS对象模型。在文档对象模型和CSS对象模型之上,创建由一组要渲染的对象组成的渲染树(这些对象在Webkit中称为渲染器或渲染对象,在Gecko中称为“框架”。)渲染树反映了DocumentObjectModel的结构,但不包含标签等元素或具有display:none属性的不可见元素。在rendertree中,每个文本字符串由一个独立的renderer表示。每个render对象包含一个对应的DOM对象,或文本块,加上计算样式。换句话说,渲染树是文档对象模型的可视化表示。对于渲染树上的每个元素,计算其坐标,这称为布局。浏览器采用流方式,布局out一个元素只需要一次pass,而table元素需要多次pass,最后渲染树上的元素最终显示在浏览器中,这个过程叫做“画图”。当用户与这个元素交互时e网页,或者脚本程序改变和修改了网页,由于网页内部结构发生了变化,上面提到的一些操作会重复进行。重绘当改变不影响元素在网页中位置的元素的样式时,如background-color(背景颜色)、border-color(边框颜色)、visibility(可见性),浏览器只会使用新样式重绘元素一次(这是重绘,或重建样式)。回流当更改影响文本内容或结构或元素放置时,会发生回流或重新布局。这些变化通常由以下事件触发:DOM操作(元素的添加、删除、修改或元素顺序的改变);内容更改,包括表单字段中的文本更改;计算或更改CSS属性;添加或删除样式表;改变“班级”;浏览器窗口的操作(缩放、滚动);伪类激活(:悬停)。浏览器如何优化渲染?浏览器试图将重新绘制/重构限制在更改元素的区域。例如,对于固定位置或绝对位置的元素,其尺寸变化只会影响元素本身及其子元素,而静态定位元素的尺寸变化将触发所有后续元素的回流。另一种优化技术是浏览器在运行多段JavaScript代码时缓存更改,并在代码运行完成后一次性应用它们。例如下面的代码只触发重构和重绘:var$body=$('body');$body.css('padding','1px');//reflow,repaint$body.css('color','red');//repaint$body.css('margin','2px');//reflow,repaint//实际上只有1reflow和repaint会发生,但是之前说过,改变元素的属性会触发强制重排。如果我们在上面的代码块中添加一行代码来访问元素的属性,就会发生这种情况。var$body=$('body');$body.css('padding','1px');$body.css('padding');//readingaproperty,aforcedreflow$body.css('color','红色');$body.css('边距','2px');结果,重排发生两次。因此,您应该将访问元素属性的操作组织在一起以优化网页性能。(您可以在JSBin中找到更详细的示例)有时,您必须触发强制回流。例如,我们必须将相同的属性(如左边距)分配给同一个元素两次。首先,它应该设置为100px,没有任何效果。然后,它必须通过过渡动画更改为50px。你现在可以在JSbin上研究这个例子,但我会在这里更详细地介绍它。首先,我们创建一个带有过渡效果的CSS类:.has-transition{-webkit-transition:margin-left1sease-out;-moz-transition:margin-left1sease-out;-o-transition:margin-left1sease-out;transition:margin-left1sease-out;}并继续://ourelementthathasa"has-transition"classbydefaultvar$targetElem=$('#targetElemId');//removethetransitionclass$targetElem.removeClass('has-transition');//changetheproperty期望过渡结束,因为课程不在那里);但是,此实现无法正常工作。所有更改都被缓存并且仅在代码块的末尾执行。我们需要的是强制重排,我们可以通过以下更改来实现://removethetransitionclass$(this).removeClass('has-transition');//changetheproperty$(this).css('margin-left',100);//triggeraforcedreflow,sothatchangesinaclass/propertygetappliedimmediately$(this)[0].offsetHeight;//一个例子,其他属性也可以工作//把transitionclassback$(this).addClass('has-transition');//changetheproperty$(this).css('margin-left',50);现在代码按预期执行。关于性能优化的实用建议总结可用材料,我提供以下建议:创建有效的HTML和CSS文件,并且不要忘记指明文档是如何编码的。样式应包含在标签中,脚本代码应添加在标签的末尾。尝试简化和优化CSS选择器(这种优化几乎被使用CSS预处理器的开发人员无视)以将嵌套级别保持在最低限度。下面是CSS选择器的性能排名(从最快的开始)1.标识符:#id2.类:.class3.标签:div4.相邻兄弟选择器:a+i5.父类选择器:ul>li6.通用选择器:*7.属性选择:input[type="text"]8.伪类和伪元素:a:hover向左原则,所以最右边的选择器应该是最快的:#idor.class:div*{...}//坏.listli{...}//坏.list-item{...}//好#list.list-item{...}//好*1.在您的脚本代码中,尽可能减少DOM操作。缓存所有内容,包括元素属性和对象(如果它们被重用)。在执行复杂的操作时,最好使用“孤儿”元素,这些元素可以在以后添加到DOM中(所谓“孤儿”元素是与DOM分离并仅存储在内存中的元素)。2.如果您使用jQuery选择元素,请遵循jQuery选择器最佳实践。3、为了改变元素的样式,修改“class”属性是有效的方法之一。执行此更改时,最好尽可能深入DOM渲染树(这也有助于将逻辑与表示分离)。4.尽量只给绝对位置或者固定位置的元素添加动画效果。5.使用滚动时禁用复杂的悬停动画(例如,在中添加一个额外的非悬停类)。读者可以参考有关此主题的文章。如果想了解更多细节,也可以阅读这两篇文章:1、浏览器是如何工作的?2、渲染:重绘、回流/重新布局、重新样式化
