今天我要将关注点放到网页渲染以及其重要性上。虽然已经有很多文章提到过这个主题了,但大部分信息都是零碎的片段。为了思考这件事情,我需要研究很多信息的来源。这也就是为什么我觉得我应该写这篇文章的原因。我相信这篇文章对新手会很有用,并且对想刷新和巩固他们已经了解的东西的高手也同样适用。
渲染应该从最开始当页面布局被定义时就进行优化,样式和脚本在页面渲染中扮演着非常重要的角色。专业人员知道一些技巧以避免一些性能问题。
这篇文章不会深入研究浏览器的技术细节,而是提供一些通用的原则。不同浏览器引擎工作原理不同,这就使特定浏览器的学习更加复杂。
我们从浏览器渲染页面的大概过程开始说起:
当在页面上修改了一些不需要改变定位的样式的时候(比如background-color
,border-color
,visibility
),浏览器只会将新的样式重新绘制给元素(这就叫一次“重绘”或者“重新定义样式”)。
当页面上的改变影响了文档内容、结构或者元素定位时,就会发生重排(或称“重新布局”)。重排通常由以下改变触发:
浏览器尽最大努力限制重排
的过程仅覆盖已更改的元素的区域。举个例子,一个 position 为 absolue 或 fixed 的元素的大小变化只影响它自身和子孙元素,而对一个 position 为 static 的元素做同样的操作就会引起所有它后面元素的重排。
另一个优化就是当运行一段Jjavascript 代码的时候,浏览器会将一些修改缓存起来,然后当代码执行的时候,一次性的将这些修改执行。举例来说,这段代码会触发一次重绘和一次重排:
- 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');
上面这段代码的结果就是,进行了
两次重排。因此,为了提高性能,你应该讲读取元素属性的代码组织在一起(
细节的例子可以看JSBin上的代码)。
有一种情况是必须触发一次强制重排的。例如:给元素改变同一个属性两次(比如margin-left
),一开始设置100px,没有动画,然后通过动画的形式将值改为50px。具体可以看例子,当然,我在这里会讲更多的细节。
我们从一个有transition的CSS class开始:
- .has-transition {
- -webkit-transition: margin-left 1s ease-out;
- -moz-transition: margin-left 1s ease-out;
- -o-transition: margin-left 1s ease-out;
- transition: margin-left 1s ease-out;
- }
然后进行实现:
- //我们的元素默认有"has-transition"属性
- var $targetElem = $('#targetElemId');
- //删除包含transition的class
- $targetElem.removeClass('has-transition');
- // 当包含transition的class已经没了的时候,改变元素属性
- $targetElem.css('margin-left', 100);
- // 再将包含transition的class添加回来
- $targetElem.addClass('has-transition');
- // 改变元素属性
- $targetElem.css('margin-left', 50);
上面的实现没有按照期望的运行。所有的修改都被浏览器缓存了,只在上面这段代码的最后才会执行。我们需要的是一次强制重排,我们可以通过进行以下修改来实现:
- //删除包含transition的class
- $(this).removeClass('has-transition');
- // 改变元素属性
- $(this).css('margin-left', 100);
- //触发一次强制重排,从而使变化了的class或属性能够立即执行。
- $(this)[0].offsetHeight; // offsetHeight仅仅是个例子,其他的属性也可以奏效。
- // 再将包含transition的class添加回来
- $(this).addClass('has-transition');
- // 改变元素属性
- $(this).css('margin-left', 50);
现在这段代码如我们所期望的运行了。
汇总了一些有用的信息,我建议以下几点:
#id
.class
div
a + i
ul > li
*
a:hover
,你应该记住浏览器处理选择器是从右向左的,这也就是为什么最右面的选择器会更快——#id
或.class
。
- div * {...} // bad
- .list li {...} // bad
- .list-item {...} // good
- #list .list-item {...} // good
:hover
动画是一个很好的主意(例如,给 body 标签加一个 no-hover 的 class)关于这个主题的文章。想了解更多的细节,可以看一下这些文章:
希望这篇文章能够对你有所帮助!
原文链接: frontendbabel 翻译: 伯乐在线 - Moejser
译文链接: http://blog.jobbole.com/72692/
名称栏目:为什么每个前端开发者都要理解网页渲染?
转载注明:http://www.mswzjz.cn/qtweb/news41/375291.html
攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能