为什么每个前端开发者都要理解页面的渲染?(转载 学习中。。。)

文章转载自:开源中国社区 [http://www.oschina.net]

今天我要将关注点放到页面渲染以及其重要性上。虽然已经有很多文章提到过这个主题了,但大部分信息都是零碎的片段。为了思考这件事情,我需要研究很多信息的来源。这也就是为什么我觉得我应该写这篇文章的原因。我相信这篇文章对新手会很有用,并且对想刷新和巩固他们已经了解的东西的高手也同样适用。

渲染应该从最开始当页面布局被定义时就进行优化,样式和脚本在页面渲染中扮演着非常重要的角色。专业人员知道一些技巧以避免一些性能问题。

这篇文章不会深入研究浏览器的技术细节,而是提供一些通用的原则。不同浏览器引擎工作原理不同,这就使特定浏览器的学习更加复杂。

浏览器是怎样渲染一个页面的?

我们从浏览器渲染页面的大概过程开始说起:

  1. 由从服务器接收到的 HTML 形成 DOM(文档对象模型)。
  2. 样式被加载和解析,形成 CSSOM(CSS 对象模型)。
  3. 紧接着 DOM 和 CSSOM 创建了一个渲染树,这个渲染树是一些被渲染对象的集合( Webkit 分别叫它们”renderer”和”render object”,而在Gecko 引擎中叫”frame”)。除了不可见的元素(比如 head 标签和一些有 display:none 属性的元素),渲染树映射了 DOM 的结构。在渲染树中,每一个文本字符串都被当做一个独立的 renderer。每个渲染对象都包含了与之对应的计算过样式的DOM 对象(或者一个文本块)。换句话说,渲染树描述了 DOM 的直观的表现形式。
  4. 对每个渲染元素来说,它的坐标是经过计算的,这被叫做“布局(layout)”。浏览器使用一种只需要一次处理的“流方法”来布局所有元素(tables需要多次处理)。
  5. 最后,将布局显示在浏览器窗口中,这个过程叫做“绘制(painting)”。

重绘

当在页面上修改了一些不需要改变定位的样式的时候(比如background-color,border-color,visibility),浏览器只会将新的样式重新绘制给元素(这就叫一次“重绘”或者“重新定义样式”)。

重排

当页面上的改变影响了文档内容、结构或者元素定位时,就会发生重排(或称“重新布局”)。重排通常由以下改变触发:

  • DOM 操作(如元素增、删、改或者改变元素顺序)。
  • 内容的改变,包括 Form 表单中文字的变化。
  • 计算或改变 CSS 属性。
  • 增加或删除一个样式表。
  • 改变”class”属性。
  • 浏览器窗口的操作(改变大小、滚动窗口)。
  • 激活伪类(如:hover状态)。

浏览器如何优化渲染?

浏览器尽最大努力限制重排的过程仅覆盖已更改的元素的区域。举个例子,一个 position 为 absolue 或 fixed 的元素的大小变化只影响它自身和子孙元素,而对一个 position 为 static 的元素做同样的操作就会引起所有它后面元素的重排。

另一个优化就是当运行一段Jjavascript 代码的时候,浏览器会将一些修改缓存起来,然后当代码执行的时候,一次性的将这些修改执行。举例来说,这段代码会触发一次重绘和一次重排:

?


1

2

3

4

5

var $body = $('body');

$body.css('padding', '1px'); // 重排, 重绘

$body.css('color', 'red'); // 重绘

$body.css('margin', '2px'); // 重排, 重绘

// 实际上只有一次重排和重绘被执行。

如上面所说,访问一个元素的属性会进行一次强制重排。如果我们给上面的代码加上一行读取元素属性的代码,这个情况就会出现:

?


1

2

3

4

5

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开始:

?


1

2

3

4

5

6

.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;

}

然后进行实现:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

//我们的元素默认有"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);

上面的实现没有按照期望的运行。所有的修改都被浏览器缓存了,只在上面这段代码的最后才会执行。我们需要的是一次强制重排,我们可以通过进行以下修改来实现:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

//删除包含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);

现在这段代码如我们所期望的运行了。

实际的优化建议

汇总了一些有用的信息,我建议以下几点:

  • 创建合法的 HTML 和 CSS ,别忘了制定文件编码,Style 应该写在 head 标签中,script 标签应该加载 body 标签结束的位置。
  • 试着简化和优化 CSS 选择器(这个优化点被大多数使用 CSS 预处理器的开发者忽略了)。将嵌套层数控制在最小。以下是 CSS 选择器的性能排行(从最快的开始):
  1. ID选择器:#id
  2. class选择器: .class
  3. 标签: div
  4. 相邻的兄弟元素:a + i
  5. 父元素选择器: ul > li
  6. 通配符选择器: *
  7. 伪类和伪元素: a:hover ,你应该记住浏览器处理选择器是从右向左的,这也就是为什么最右面的选择器会更快——#id.class

?


1

2

3

4

div * {...} // bad

.list li {...} // bad

.list-item {...} // good

#list .list-item {...} // good

  1. 在你的脚本中,尽可能的减少 DOM 的操作。把所有东西都缓存起来,包括属性和对象(如果它可被重复使用)。进行复杂的操作的时候,最好操作一个“离线”的元素(“离线”元素的意思是与 DOM 对象分开、仅存在内存中的元素),然后将这个元素插入到 DOM 中。
  2. 如果你使用 jQuery,遵循jQuery 选择器最佳实践
  3. 要改变元素的样式,修改“class”属性是最高效的方式之一。你要改变 DOM 树的层次越深,这一条就越高效(这也有助于将表现和逻辑分开)。
  4. 尽可能的只对 position 为 absolute 或 fix 的元素做动画。
  5. 当滚动时禁用一些复杂的 :hover 动画是一个很好的主意(例如,给 body 标签加一个 no-hover 的 class)关于这个主题的文章

想了解更多的细节,可以看一下这些文章:

  1. How browsers work
  2. Rendering: repaint, reflow/relayout, restyle

希望这篇文章能够对你有所帮助!

原文链接: frontendbabel   翻译: 伯乐在线Moejser
译文链接: http://blog.jobbole.com/72692/

时间: 2024-10-22 19:37:01

为什么每个前端开发者都要理解页面的渲染?(转载 学习中。。。)的相关文章

为什么每个前端开发者都要理解页面的渲染?

渲染应该从最开始当页面布局被定义时就进行优化,样式和脚本在页面渲染中扮演着非常重要的角色.专业人员知道一些技巧以避免一些性能问题. 这篇文章不会深入研究浏览器的技术细节,而是提供一些通用的原则.不同浏览器引擎工作原理不同,这就使特定浏览器的学习更加复杂. 浏览器是怎样渲染一个页面的? 我们从浏览器渲染页面的大概过程开始说起: 由从服务器接收到的 HTML 形成 DOM(文档对象模型). 样式被加载和解析,形成 CSSOM(CSS 对象模型). 紧接着 DOM 和 CSSOM 创建了一个渲染树,这

有关网页渲染,每个前端开发者都该知道的那点事

[编者按]其实,有关网页渲染的文章很多,但是相关信息比较分散,且论述并不是很完整.如果要想对这个主题有个大致的了解,我们还得学习很多知识.因此,Web开发者Alexander Skutin 决定写一篇文章.他相信,这篇文章不仅能帮助初学者,也能对那些想要刷新知识结构的高级前端开发者有所裨益.原文地址 译文如下: 网页渲染必须在很早的阶段进行,可以早到页面布局刚刚定型.因为样式和脚本都会对网页渲染产生关键性的影响.所以专业开发者必须了解一些技巧,从而避免在实践的过程中遇到性能问题. 这篇文章不会研

JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(转载 学习中。。。)

作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript. JavaScript作用域 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.在JavaScript中,变量的作用域有全局作用域和局部作用域两种. 1.  全局作用域(Global S

2014年前端开发者如何提升自己

大部分人非常在意个人在技术上的提升.但是保持对新技术的了解是一项不小的挑战, 毕竟我们需要的信息在数量上过于庞大.2012年里,伴随着前端发展的是大量的革命性突破和对前端的重新定义. 我们在实践的路上飞速前进,具体的进步体现在使用抽象化,优秀的代码质量,维护性上的提升以及更好的性能.如果你实在忙到没有时间来跟上最新的技术,不用担心. 随着假日的来临,我们就有了一些空闲的时间可以自己支配,我想,如果我把我收集的前端相关的精品讨论列表分享出来,那一定会对大家有一些帮助.你不需要把所有的都阅读一遍,但

每个Javascript开发者都应当知道的那些事

每个Javascript开发者都应当知道的那些事 2015-06-07 前端大全 (点击上方蓝字,可快速关注我们) Javascript是一种日益增长的语言,特别是现在ECMAScript规范按照每年的发布时间表发布.伴随着这门语言的规模化和快速发展,掌握JS(不仅仅是jQuery)的重要性,变得更加重要. 这不是一篇自称是 JS 开发者知识圣杯的权威指南.不过里面绝对有一些我曾经错过的,有一些我可能是错用的,还有一些你可能不同意每个JS开发者应该知道的东西. 如何FizzBuzz 译者注:Fi

20个为前端开发者准备的文档和指南

20个为前端开发者准备的文档和指南 来源:codeceo 发布时间:2016-07-27 阅读次数:358 0 是时候重新学习了!和以前一样,我收集了很多不同的学习资源,包括学习指南,学习文档,和其他有用的网站来帮助你在前端开发的不同领域里快速地进入状态. 所以请尽情享受我们的文档和指南系列的第九部分,并且不要忘了在评论区让我知道任何我没有找到的. 1. JavaScript Standard Style(JavaScript标准样式) 链接:http://standardjs.com Java

移动前端开发者必知必会:移动设备概述

由于工作岗位的变换带来工作内容的变动,对于移动站点的前端开发已经疏远了好几个月,在这好几个月中有非常多新的东西出现,自己所掌握的一些东西也已经陈旧,所以选择了这本书<HTML5触摸界面设计与开发>来系统地学习和整理一下关于移动站点前端开发的知识体系. 之所以选择这本书,一是由于这本书比較新,2014年04月发的第一版.其二是由于作者Stephen Woods,这是Flickr团队的资深前端,Yahoo主页的Javascript技术平台正是出自此人之手. 接下来的时间里会陆续上传关于这本书学习的

每个PHP开发者都应该看的书

PHP这几年口碑很差.关于它的“糟糕设计的汇总”和语法上的矛盾有着大量的讨论,但是主要的抱怨通常是安全.很多PHP站点分分钟被黑掉,甚至一些有经验的.有见识的程序员会说,这门语言本身是不安全的. 我总是对此持反对意见,因为有常识性的原因,有如此多的PHP安全违反现象. PHP应用程序经常被黑掉是由于: PHP应用程序太多了. 它易于学习和编写. 糟糕的PHP也容易编写. 就是这么简单.PHP流行好多年了.PHP越是受欢迎,它被发现的漏洞就越多.这些黑客发现的漏洞很少是PHP处理引擎本身的,通常是

前端开发者不得不知的ES6十大特性

前端开发者不得不知的ES6十大特性 转载 作者:AlloyTeam 链接:http://www.alloyteam.com/2016/03/es6-front-end-developers-will-have-to-know-the-top-ten-properties/ ES6(ECMAScript2015)的出现,无疑给前端开发人员带来了新的惊喜,它包含了一些很棒的新特性,可以更加方便的实现很多复杂的操作,提高开发人员的效率. 本文主要针对ES6做一个简要介绍. 主要译自:  http://