Home  >  Article  >  Web Front-end  >  提高Web页面性能的技巧_html/css_WEB-ITnose

提高Web页面性能的技巧_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-24 11:28:00952browse

现在 动辄几兆大小的页面加载量 ,让性能优化成了不可避免的热门话题。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 面板中:

所有的浏览器都使用绿色来显示页面重绘和页面回流事件。上面的测试只是几个简单的示例,其中没有调用繁重的动画效果,所以布局渲染在总时间中占据了较大比重。减少页面回流和页面重绘,自然提高页面性能。

本文根据 @Craig Buckler 的《 10 Ways to Minimize Reflows and Improve Performance 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: http://www.sitepoint.com/10-ways-minimize-reflows-improve-performance/ 。

南北

前端开发者,关注性能优化和动效设计,活跃于 Github @pinggod 、微博@ping4god 和博客 pinggod.com ,替身众多。如果你沉醉于 Kairosoft、午时三刻工作室的游戏,请来和我做朋友:)。

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn