现在动辄几兆大小的页面加载量,让性能优化成了不可避免的热门话题。WEB 应用越流畅,用户体验就会越好,继而带来更多的访问量。这也就是说,我们应该反省一下那些过度美化的 CSS3 动画和多重操作的 DOM 元素是否都考虑到了在性能方面的影响。在说性能优化之前,我们有必要理清浏览器视觉绘制方面的两个术语:

Repaint(重绘):如果某些操作影响了 DOM 元素的可见性,但又没有影响布局,那么就会发生浏览器的重绘,比如opacity,background-color,visibility 和 outline 属性。由于浏览器必须检查 DOM 中所有节点的可见性——某些图层或许会置于重绘元素的图层下面,所以重绘是一个非常繁重的逻辑。
Reflow(回流):回流是一个更具破坏性的操作,它会让浏览器重新计算所有元素的坐标位置和尺寸大小。往往由于一个元素的变化,继而引起其子元素、父元素以及相邻元素的变化。

不管用户或者应用本身是否正在执行某些逻辑,这两种操作都会阻塞浏览器进程。极端情况下,一个 CSS 效果会降低 JavaScript 的执行速度。下面是触发回流事件的几种情境:

添加、删除和修改可见的 DOM 元素
添加、删除和修改部分 CSS 样式,比如修改元素的宽度,会影响其相邻元素的布局位置
CSS3 动画和过渡效果
使用 offsetWidth 和 offsetHeight。这种情境很诡异,读取一个元的 offsetWidth 和 offsetHeight 属性会触发回流
用户行为,比如鼠标悬停、输入文本、调整窗口大小、修改字体样式等等

浏览器的底层实现各有不同,所以渲染页面的开销也各有轻重。好在我们有一些通常规则可以进行性能优化。

使用最佳实践所建议的布局技巧

虽然已经是 2015 了,但我还是要说不要使用行内联样式和 table 布局。
HTML 文档下载完成后,行内样式会触发一次额外的回流事件。解析器在解析 table 布局时需要计算大量的单元格的尺寸,所以是件很重的操作。由于单元格往往是根据表头宽度确定的,所以使用 table-layout: fixed 可以缓解部分性能消耗。

使用 Flexbox 布局也存在性能损失,因为在页面加载完成后,flex item 可能会发生位置和尺寸的变化。

精简 CSS 样式

样式越少,回流越快,此外,尽量不要使用过于复杂的选择器。这一问题尤其突出在使用类似 Bootstrap 框架的网站上。使用Unused CSS,uCSS,grunt-uncss 和 gulp-uncss 等工具可以有效剔除无用样式。

精简 DOM 层级

精简 DOM 层级,指的是减少 DOM 树的级数已经每一分支上 DOM 元素的数量,结果就是层级越少、数量越少,回流越快。此外,如果无需考虑旧版本浏览器,应该尽量剔除无意义的包裹类标签和层级。

细粒度操作 DOM 树

操作 DOM 树时的粒度要尽可能细化,这有助于减弱局部 DOM 变化给整体带来的影响。

从文档流中移除复杂的动画效果

应该确保使用动画的元素脱离了文档流,使用 position: absolute 和 position: fixed 属性脱离文档流的元素会被浏览器创建一个新层来存放,这些图层上的修改不会影响其他图层上的元素。

巧用隐藏方式

使用 display: none; 隐藏的元素不会触发页面的重绘和回流事件,所以可以在这些元素隐藏期间配置样式,配置完成后再转换为可见状态。

批量更新元素

单词更新所有 DOM 元素的性能要优于多次更新。下面这段代码触发了三次页面回流:

var myelement = document.getElementById('myelement');
myelement.width = '100px';
myelement.height = '200px';
myelement.style.margin = '10px';

通过以下代码可以精简为一次页面回流事件,并且提高了代码的可维护性:

var myelement = document.getElementById('myelement');
myelement.classList.add('newstyles');

.newstyles {
width: 100px;
height: 200px;
margin: 10px;
}

同理,我们还可以减少操作 DOM 的频率。假设我们要创建一个如下所示的无序列表:

如果分次添加每一个 item 将会触发多次页面回流,简单而高效的方式是使用 DOM fargment 在内存中创建完整的 DOM 节点,然后一次性添加到 DOM 中:

var

i, li,

frag = document.createDocumentFragment(),

ul = frag.appendChild(document.createElement('ul'));

for (i = 1; i <= 3; i++) {

li = ul.appendChild(document.createElement('li'));

li.textContent = 'item ' + i;

}

document.body.appendChild(frag);

约束元素变化的影响

这里的约束是指,尽量避免某个元素的变化引起大范围的变化。假设我们有一个 tab 选项卡的组件,选项卡内部的内容长短不一,这就导致了每个选项卡的高度不唯一。这一设计带来的问题就是每次切换选项卡时,周围的元素都要重新布局。我们可以通过一个固定高度来避免这一情况。

权衡流畅度和性能

一次移动一像素的位置看起来虽然很流畅,但对于某些低性能终端会是很大的压力。一次移动四像素降低帧速虽然看起来稍有些迟钝,但性能压力降低了。这就是需要我们权衡的地方:流畅度和性能。

使用开发者工具分析页面重绘

目前主流浏览器都在开发者工具中提供了监控页面重绘的功能。在 Blink/Webkit 内核的浏览器中,使用 Timeline 面板可以记录一个页面活动详情:

下面是火狐开发者工具中的 TimeLine:

在 IE 中这个功能被放置在了 UI Responsiveness 面板中:

作者:南北
链接:http://www.w3cplus.com/performance/10-ways-minimize-reflows-improve-performance.html

提高Web页面性能的技巧的更多相关文章

  1. 提高 DHTML 页面性能

    联盟电脑摘要:本文说明了某些DHTML功能对性能的重大影响,并提供了一些提高DHTML页面性能的技巧. 目录 简介 成批处理DHTML更改 使用innerText 使用DOM添加单个元素 扩展SELE ...

  2. 25条提高iOS App性能的技巧和诀窍

    25条提高iOS App性能的技巧和诀窍 当我们开发iOS应用时,好的性能对我们的App来说是很重要的.你的用户也希望如此,但是如果你的app表现的反应迟钝或者很慢也会伤害到你的审核. 然而,由于IO ...

  3. 隔壁老主精讲web页面性能优化。

    首先说一下为什么要进行web页面性能优化,在同样的网络环境下,两个同样能满足你的需求的网站,一个“Biu”的一下就加载出来了,一个卡--卡--卡--卡--卡--才出来,你会选择哪个?研究表明:用户最满 ...

  4. 微信移动端web页面调试小技巧

    技术贴还是分享出来更加好,希望能对一些朋友有帮助,个人博客  http://lizhug.com/mymajor/微信移动端web页面调试小技巧

  5. Web页面性能优化(YSlow)

    YSlow(解析为Why Slow)是雅虎基于网站优化规则推出的工具,帮助你分析并优化网站性能.旧版Yslow 有13条规则,新版Yslow有23项规则,YSlow会根据这些规则分析你的网站,并给出评 ...

  6. 如何提高web页面的性能

    1.浏览器渲染原理解析 想要提高网页的性能,首要的便是要理解浏览器渲染原理,下面关于浏览器的原理解析,我们以chrome内核webkit为例,其他内核的浏览器原理也基本大同小异,可触类旁通. 如上图所 ...

  7. 提高 web 应用性能之 CSS 性能调优

    简介 Web 开发中经常会遇到性能的问题,尤其是 Web 2.0 的应用.CSS 代码是控制页面显示样式与效果的最直接“工具”,但是在性能调优时他们通常被 Web 开发工程师所忽略,而事实上不规范的 ...

  8. [转]提高 web 应用性能之 CSS 性能调优

    简介 Web 开发中经常会遇到性能的问题,尤其是 Web 2.0 的应用.CSS 代码是控制页面显示样式与效果的最直接“工具”,但是在性能调优时他们通常被 Web 开发工程师所忽略,而事实上不规范的 ...

  9. web页面性能优化

    web前端页面性能优化 网站的划分一般为二:前端和后台.我们可以理解成后台是用来实现网站的功能的,比如:实现用户注册,用户能够为文章发表评论等等.而前端呢? 其实应该是属于功能的表现.并且影响用户访问 ...

随机推荐

  1. CSS中nth-child和nth-of-type的简单使用

    ele:nth-child是查找父元素下的子元素,包括子元素类型非ele的,当子元素类型不是ele时,则不会进行任何操作: ele:nth-of-type是查找父元素下的子元素类型为ele的元素,其是 ...

  2. 使用JQuery双击修改Table中Td

    <html> <head> <meta http-equiv="Content-Type" content="text/html;chars ...

  3. 一个简单的将GUI程序的log信息输出到关联的Console窗口中(AllocConsole SetConsoleTitle WriteConsole 最后用ShowWindow(GetConsoleWindow)进行显示)

    // .h 文件 #pragma once class CConsoleDump { public: explicit CConsoleDump(LPCTSTR lpszWindowTitle = N ...

  4. QTP之delphi试用感想一(自动化测试)

    这两天一直在琢磨自动化测试,自动化测试,其实与单元测试有一些相同之处,单元测试的目的也是可以一次写,多次运行,对于测试驱动及后期维护真是有非常多的好处,用自动化测试工具也是如何,主要目的是为了回归测试 ...

  5. JS中用execCommand("SaveAs")保存页面兼容性问题解决方案

    开发环境:ASP.NET MVC,其他环境仅供参考. 问题描述:在开发中遇到这样的需求,保存页面,通常使用JavaScript的saveAs进行保存,各浏览器对saveAs支持,见下表. 代码一:初始 ...

  6. 尝鲜delphi开发android/ios_环境搭建

    Delphi这又老树发新枝了,开始做终端程序开发了,这个东西的准确名字是:RAD Studio XE5,可以使用delphi和c++ builder进行终端开发. 我尽可能讲啰嗦一些,免得回头被人问. ...

  7. jQuery $.post $.ajax用法

    jQuery $.post $.ajax用法 jQuery.post( url, [data], [callback], [type] ) :使用POST方式来进行异步请求 参数: url (Stri ...

  8. 分批次获取git for windows的源代码

    $ git initInitialized empty Git repository in d:/SourceCode/GitHub/Git For Windows/Git/.git/ $ git r ...

  9. [POJ3177]Redundant Paths(双连通图,割边,桥,重边)

    题目链接:http://poj.org/problem?id=3177 和上一题一样,只是有重边. 如何解决重边的问题? 1.  构造图G时把重边也考虑进来,然后在划分边双连通分量时先把桥删去,再划分 ...

  10. JasperReports+iReport在eclipse中的使用

    转载:http://blog.csdn.net/daming924/article/details/7402295 一.介绍1)它可以PDF,HTML,XML等多种形式产生报表或动态报表,在新版本还支 ...