5-优化浏览器呈现
来源:互联网 发布:淘宝网中老年春秋女装 编辑:程序博客网 时间:2024/06/10 08:52
http://code.google.com/intl/zh-CN/speed/page-speed/docs/rendering.html
一旦资源被下载到客户端,浏览器依然需要去加载、解析和呈现 HTML、CSS 和 Javascript 代码。根据当前浏览器的特点简单格式化你的代码和页面, 就可以在客户端这边增强性能。
- 使用高效的 CSS 选择器(Useefficient CSS selectors)
- 避免 CSS 表达式(Avoid CSSexpressions)
- 把 CSS 放在文档的头部(Put CSS in thedocument head)
- 指定图片尺寸(Specifyimagedimensions)
- 尽早指定字符集(Specify acharacter set early)
使用高效的 CSS 选择器(Use efficient CSSselectors)
概览
避免用效率低下的关键选择器匹配大量元素,这样能极大提高页面呈现速度(原文:Avoiding inefficient key selectors that match large numbers ofelementscan speed up page rendering.)。
详情
浏览器解析 HTML 时,它构建了一个内部的文档树,用以表示即将呈现到页面上的所有元素。然后按照 CSS 级联、继承、顺序标准来匹配样式表给元素定义的样式。Mozilla(可能其他浏览器也一样)的 CSS 引擎搜索依照你定义的样式规则为每个元素找到匹配的样式 。CSS 引擎自右向左评估每个规则,从最右边的选择器(叫做“键(key)”)开始遍历每个选择器,直到找到一个匹配规则或决定抛弃该规则。(“选择器”是样式规则所要应用的那个文档元素。)
按这个思路,规则越少,引擎评估起来越快。当然,要提高页面呈现速度,移除无用的 CSS 也是一个十分重要的步骤。之后,对包含大量元素的页面(或者含有大量 CSS 规则的页面),优化定义规则本身也能极大提高性能。优化规则的关键是定义规则时尽可能具体,避免不必要的冗余,让样式引擎快速的匹配而不要花时间评估这个规则是不是可以应用。
以下各种规则是效率低下的:
- 规则中含有后代选择器(Rules with descendant selectors)
- 例如:
- 规则中把通用选择器作为关键字(key)
body * {...}
.hide-scrollbars * {...}- 规则中把标签选择器作为关键字
ul li a {...}
#footer h3 {...}
* html #atticPromo ul li a {...}
后代选择器的效率不高,因为浏览器为每个元素匹配关键字时,都必须遍历整个 DOM 树,评估每个祖先元素,直到到达根元素才能找到合适的匹配。关键字定义的越不具体,评估时要遍历的节点就越多。
- 规则中含有子选择或相邻选择器(Rules with child or adjacent selectors)
- 例如:
- 规则中含有通用选择器关键字(Rules with the universal selector as the key)
body > * {...}
.hide-scrollbars > * {...}- 规则中含有标签选择器关键字(Rules with a tag selector as the key)
ul > li > a {...}
#footer > h3 {...}
子选择器和相邻选择器是无效的,因为浏览器匹配元素的时候仍需要评估其他节点 。规则中含有子选择器的代价更加昂贵。同样的,关键字定义的越不具体,评估时要遍历的节点就越多。不过,即使效率不够,他们仍然是性能较好的后代选择器(原文:However, while inefficient, they are still preferableto descendant selectors in terms of performance.)。
- 规则中含有过于精确的选择器(Rules with overly qualified selectors)
- 例如:
ul#top_blue_nav {...}
form#UserLogin {...}ID 选择器是唯一定义的。附加额外的标签(tag)预选器或 class 预选器所增加的冗余信息都会增加不必要的评估量。
- 给非链接元素添加
:hover
伪选择器的规则(Rules that apply the:hover
pseudo-selector to non-link elements) - 例如:
h3:hover {...}
.foo:hover {...}
#foo:hover {...}
div.faa :hover {...}众所周知,有时*,给非链接元素添加
:hover
伪选择器会使得 IE7 和 IE8 变慢。如果你的文档类型不够严谨,IE7 和 IE8 会忽略附加在除了锚(anchor)之外的所有元素上的:hover
。如果你的文档结构严谨,附加在非链接之上的:hover
会导致性能下降。* 请查看有关 bug 报告:http://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=391387.
推荐
- 避免通用选择器(Avoid a universal key selector)
- 允许元素继承祖先的规则,或者给多个元素应用 class 定义的样式。
- 规则定义要尽可能具体(Make your rules as specific as possible)
- 使用 class 和ID 选择器比使用 tag 选择器更好。
- 删除冗余的预选器(Remove redundant qualifiers)
- 这些预选器是冗余的:
- 被 class 和/或 标签选择器定义过的 ID 选择器
- 被标签选择器定义过的 class 选择器(好的设计是:一个标签仅有一个 class)。
- 避免使用后代选择器,尤其是那些被冗余定义的祖先的后代(Avoid using descendant selectors, especially those thatspecify redundant ancestors)
- 例如,如下规则
body ul li a {...}
定义了一个冗余的body
选择器,因为所有元素都是body
标签的后代。 - 使用 class 选择器代替后代选择器(Useclass selectors instead ofdescendant selectors)
- 例如,如果你要为有序列表项(ordered list item)两个不同的样式,不要这样定义:
ul li {color: blue;}
ol li {color: red;}你应当为这两个样式定义两个 class ,然后在你的规则中应用它们,例如:
.unordered-list-item {color: blue;}
.ordered-list-item {color: red;}如果你必须使用后代选择器,优先使用子选择器(childselectors),这样,仅需要额外评估一个节点,而不是评估直到祖先的所有中间节点。
- 对 IE 客户端,避免对非链接元素使用
:hover
伪选择器 - 如果在非链接元素上使用
:hover
伪选择器,请在 IE7 和 IE8 下测试该页面,以确保该页面是可用的。如果你发现:hover
导致了性能下降,考虑为 IE 客户端使用 JavaScript 的onmouseover
事件处理。
附加资源
- 更多的 Mozilla 高效 CSS 规则,参见:WritingEfficient CSS for Use in the Mozilla UI。
- 完整的 CSS 信息,参见:CascadingStyle Sheets Level 2 Revision 1 (CSS 2.1) Specification。CSS 选择器规范,参见Chapter5.
避免 CSS 表达式(Avoid CSS expressions)
概览
CSS 表达式会降低渲染(页面呈现)性能;对 IE 用户来说,用其他方式代替 CSS 表达式会加速浏览器呈现速度。
注意:本节的最佳实践仅仅针对 IE 5 到 IE 7(它们支持 CSS 表达式)。IE 8 不推荐 CSS 表达式,其他浏览器不支持 CSS 表达式。
详情
IE 5 引入了 CSS 表达式,或曰“动态属性”,用来根据事件的不同响应动态改变文档属性。CSS 表达式包括嵌入的 JavaScript 表达式,JS 表达式输出 CSS 声明中的属性值。多数情况下,CSS 表达式用于一下目的:
- 模仿其他浏览器所支持的标准 CSS 属性(其实 IE 自己也没有支持下去)。
- 以一种更紧凑哦更便捷的方式提供动态样式和高级事件处理,而不必写完整的 JavaScript 注入样式。
不幸的是,可以想象其执行性能给 CSS 表达式判了极刑,因为触发任何一个事件,浏览器都要重新评估每个表达式,例如:重新调整窗口大小、鼠标移动事件等。CSS 表达式的低性能是 IE 8 放弃支持的一个原因。如果你在页面中用过 CSS 表达式,就要努力的删除它们,用其他实现手段实现同样的功能。
推荐
- 尽可能使用标准 CSS 属性(Use standard CSS properties if possible)
- IE 8 全面兼容 CSS 标准;仅在“兼容”模式下执行 CSS 表达式,在“标准”模式下不执行。如果你不需要维护向下兼容的旧版 IE,你要改写所有的表达式实例,用标准 CSS 行为的标准 CSS 属性替换它们。完整的 CSS 属性列表以及支持它们的 IE 版本,参见 MSDN CSSAttributes Index。如果你确实需要支持旧版的 IE,你需要的某些 CSS 属性可能不存在,请用 JavaScript 实现同样的功能。
- 使用 JavaScript 处理样式(Use JavaScript to script styles)
- 如果为了动态处理样式而使用 CSS 表达式,请用纯粹的 JavaScript 重写,这样不但能提高在 IE 中的性能,还能在其他浏览器获得同样功能。关于动态属性,MSDN 网页给出的例子是:CSS 表达式用在要居中显示的 HTML 块之上,该 HTML 块在运行期间会改变尺寸,而且窗口尺寸每发生改变这个 HTML 块都需要重新居中:
<div id="oDiv" style="background-color: #CFCFCF; position: absolute;
left:expression(document.body.clientWidth/2-oDiv.offsetWidth/2);
top:expression(document.body.clientHeight/2-oDiv.offsetHeight/2)">Example DIV</div>下面是用 JavaScript 和标准 CSS 实现的等效的功能:
<style>
#oDiv { position: absolute; background-color: #CFCFCF;}
</style>
<script type="text/javascript">
// Check for browser support of event handling capability
if (window.addEventListener) {
window.addEventListener("load", centerDiv, false);
window.addEventListener("resize", centerDiv, false);
} else if (window.attachEvent) {
window.attachEvent("onload", centerDiv);
window.attachEvent("onresize", centerDiv);
} else {
window.onload = centerDiv;
window.resize = centerDiv;
}
function centerDiv() {
var myDiv = document.getElementById("oDiv");
var myBody = document.body;
var bodyWidth = myBody.offsetWidth;
//Needed for Firefox, which doesn't support offsetHeight
var bodyHeight;
if (myBody.scrollHeight)
bodyHeight = myBody.scrollHeight;
else bodyHeight = myBody.offsetHeight;
var divWidth = myDiv.offsetWidth;
if (myDiv.scrollHeight)
var divHeight = myDiv.scrollHeight;
else var divHeight = myDiv.offsetHeight;
myDiv.style.top = (bodyHeight - divHeight) / 2;
myDiv.style.left = (bodyWidth - divWidth) / 2;
}
</script>如果你用 CSS 表达式模仿早期 IE 版本不支持的 CSS 属性,这种情况下,你应当提供 JavaScript 代码,并禁用浏览器支持 CSS 进行测试。例如,
max-width
属性,会迫使文本在指定像素宽度下折行,该属性直到 IE 7 才得到支持。IE 5 和 6 提供了解决方法:p { width: expression( document.body.clientWidth > 600 ? "600px" : "auto" ); }
对不支持
max-width 属性的
IE,可以用类似下面这样的代码,用等效的 JavaScript 替换 CSS 表达式:<style>
p { max-width: 300px; }
</style>
<script type="text/javascript">
if ((navigator.appName == "Microsoft Internet Explorer") && (parseInt(navigator.appVersion) < 7))
window.attachEvent("onresize", setMaxWidth);
function setMaxWidth() {
var paragraphs = document.getElementsByTagName("p");
for ( var i = 0; i < paragraphs.length; i++ )
paragraphs[i].style.width = ( document.body.clientWidth > 300 ? "300px" : "auto" );
</script>
把 CSS 放在文档的头部(Put CSS in the document head)
概览
把出现在文档体中的内联样式块和<link>元素移动到文档头部,以提高渲染性能。
详情
定义在 HTML 文档体的外部样式表和内联样式块对浏览器渲染性能会产生负面的影响。直到所有的外部样式表下载完毕,浏览器才不会阻止页面的呈现。内联样式块(<style>标签定义的)会引起内容的回流(reflow)和转移(shifting)。因此,在文档头部指向外部样式表和内联样式块是十分重要的。确保样式表首先被加载和解析,浏览器将会逐步呈现页面。
推荐
- 按照 HTML 4.01 规范(12.3节)的要求,在<head>节内使用<link>标签引入外部样式表。不要使用
@import
。同时也要确保你定义的样式表和脚本以正确的顺序出现。 - 把<style>块放在<head>节内。
指定图片的尺寸(Specify image dimensions)
概览
给所有的图片指定宽度和高度,排除不必要的回流和重画,会提高页面呈现速度。
详情
浏览器布局页面的时候,需要把诸如图片之类的可替换元素放入流中。在图片下载完之前,浏览器就开始呈现页面,并按照浏览器所知道的尺寸折行呈现那些不可替代的元素(原文:It can begin to rendera page even before images are downloaded, provided that it knows thedimensions to wrap non-replaceable elements around.)。如果没有定义图片的具体尺寸,或者定义的尺寸不匹配实际图片的大小,在图片下载完成之后,浏览器会请求回流和重画。为了防止回流,请在 HTML 的<img>标签或者在 CSS 中具体定义图片的宽度和高度。
推荐
- 具体制定匹配图片的尺寸(Specifydimensions that match those of the images themselves)
- 不要缩放图像(to scale images on the fly)。如果一个图片文件实际尺寸是 60 x 60 像素,不要在 HTML 或 CSS 中把它设置成 30 x 30 像素。如果需要图像的小尺寸图,请在图片编辑器中编辑好,然后再为它设置匹配的尺寸(具体参见优化图片)。
- 确保尺寸定义在图片元素或其块级别的父元素上(Be sure to specify dimensions on the image element orblock-level parent)
- 确保尺寸定义在<img>元素自身或其块级别的父元素之上。如果父元素不是块级别元素,定义的尺寸会被忽略。不要给锚(ancestor)设置尺寸,它不是图片元素的直接父元素(原文:Do not set dimensions on an ancestor that is not an immediate parent.)。
尽早指定字符集(Specify a character set early)
概览
尽早为 HTML 文档指定字符集,这样浏览器就可以立即执行脚本。
详情
HTML 文档以携带字符编码信息的字节序列的形式在因特网中传递。字符编码信息具体指定在 HTTP 响应的头部,或在文档本身的 HTML 标签之中。浏览器依据字符编码信息把字节流转化为最终呈现在屏幕上的字符。因为浏览器不知道如何构建页面字符集就没法正确渲染页面,大多数浏览在执行 JavaScript 或画页面之前都会缓冲一些字节,当浏览器找到字符集信息之后再填充这些缓冲字节中。(一个值得注意的例外是 IE 6、7 和 8。)
不同浏览器缓冲的字节数不同,没有找到字符集时默认的编码方式也不同。不过,一旦浏览器缓冲了必要的字节数,就开始呈现页面了。如果浏览器遇到指定的字符集不匹配默认设置,浏览器会重写分析输入流并重画页面(原文:if they encounter a character setspecification that doesn't match their default, they need to reparsethe input and redraw the page.)。有时,如果失配影响到了外部资源的 URL,浏览器甚至不得不重新请求资源。
为避免这些延时,对任何 超过 1KB(1024字节,确切的说,在我们做的浏览器的所有测试中,这是最大的缓冲限制) 的 HTML 文档都应当尽早指定字符编码。
推荐
- 设置 HTTP 比设置 meta 标签参数要好(Prefer HTTP over meta tag parameters)
- 有几种方法给 HTML 文档指定字符集:
- 服务端:配置你的 web 服务器,给所有
text/html 类型文档的
Content-Type 头部配置
charset
参数,指定正确的字符编码,例如:Content-Type: text/html; charset=UTF-8
- 客户端:HTML 代码的 meta 标签内设置属性
http-equiv="content"
,指定charset
参数,例如:<meta http-equiv="Content-Type"content="text/html;charset=utf-8">
- 服务端:配置你的 web 服务器,给所有
- 在网页头部片段内具体定义 meta 标签(Specify the meta tag at the top of the head section)
- 如果你不控制你的 web 服务器配置,又需要在 meta 标签内设置字符集,一定要写在文档<head>片的顶部。浏览器会在文档的钱 1024 字节内查找这样的字符集参数,所以,为了避免性能损失,这个参数一定要在尽早出现在文档的头部。
- 始终指定内容类型(Always specify a content type)
- 在浏览器开始检查字符集之前,必须先确定待处理文档的内容类型(content-type)。如果没有在 HTTP 头部或 HTML meta 标签指明,浏览器会用某些算法“嗅嗅”这个类型。这个过程会导致额外的延时,除非出现了安全漏洞。不管出于性能还是安全理由,你都应当为所有资源指明内容类型(不仅仅是文本或 HTML)。
- 确保用正确的字符集编码(Be sure to specify the correctcharacter encoding)
- 你在 HTTP 头部 或 HTML meta 标签中定义字符集将用来书写 HTML 文档,这点十分重要。如果你在 HTTP 头部和 HTML meta 标签中都指定了字符集,请让两者保持一致。如果浏览器侦测到不正确或不匹配的编码,浏览器会按照错误的编码来渲染网页,并/或产生额外的延时以便重画页面。关于可用字符集的更多信息,参见HTML4.01 规范的字符集编码 5.2节。
附加资源
是否使用 content-type 和 字符集对浏览器行为的具体影响,参见:
- PageSpeed wiki
- 字符集带来的浏览器性能问题(BrowserPerformance Issues with Charsets)
- 字符集的性能影响(PerformanceImplications of "charset")
译者主页
www.our3w.com/ddm
- 5-优化浏览器呈现
- 浏览器内核、JS 引擎、页面呈现原理及其优化
- js学习小结(七)2014.5.5(识别呈现引擎、浏览器版本和操作平台)
- input file 在不同浏览器中的呈现
- 浏览器构建呈现树的流程
- js 检测浏览器,呈现引擎和平台
- 【学习点滴-js】js 检测浏览器,呈现引擎和平台。
- 解决IE浏览器不支持CSS样式呈现的问题
- 输入url到浏览器呈现页面的过程
- WPF如何提升三维呈现性能及优化
- Flash 平台技术的优化(十三) 呈现文本对象
- 浏览器优化中的2-5-8原则
- 修复“资源浏览器”的浏览器栏区域呈现灰色空白问题
- 浏览器识别(包括呈现引擎,浏览器版本,操作系统,移动设备)
- 网站策划呈现的5个趋势
- iOS基础5:常见呈现模式
- 浏览器速度优化
- 优化浏览器渲染
- 3 最小化请求开销
- 4-最小化有效负荷的大小
- 有用的网站
- PB API调用指南
- 推荐40个互联网知名博客
- 5-优化浏览器呈现
- betwin V.419 实现一台电脑变两台!实用设置案例
- 解决Linux计划任务不能运行的问题
- 用Doctype激活浏览器模式(Activating Browser Modes with Doctype) (三)
- oracle排序问题
- RVDS与MDK-ARM比较
- 解决Linux Samba服务器共享不能进行写操作的问题
- zoj 1149 || poj 1014 Dividing(多重背包)
- 如何安装GCC 4.5.2(尚未成功)