前端渲染优化,移动HTML 5前端性能优化指南( 二 )


$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);
现在这段代码如我们所期望的运行了 。
实际的优化建议
汇总了一些有用的信息,我建议以下几点:
· 创建合法的 HTML 和 CSS,别忘了制定文件编码,Style 应该写在 head 标签中,script 标签应该加载 body 标签结束的位置 。
· 试着简化和优化 CSS 选择器(这个优化点被大多数使用 CSS 预处理器的开发者忽略了) 。将嵌套层数控制在最小 。以下是 CSS 选择器的性能排行(从最快的开始):
ID选择器:#id
class选择器: .class
标签: div
相邻的兄弟元素:a + i
父元素选择器: ul > li
通配符选择器: *
伪类和伪元素: a:hover,你应该记住浏览器处理选择器是从右向左的,这也就是为什么最右面的选择器会更快——#id或.class 。
div * {...} // bad
.list li {...} // bad
.list-item {...} // good
#list .list-item {...} // good
在你的脚本中,尽可能的减少 DOM 的操作 。把所有东西都缓存起来,包括属性和对象(如果它可被重复使用) 。进行复杂的操作的时候,最好操作一个“离线”的元素(“离线”元素的意思是与 DOM 对象分开、仅存在内存中的元素),然后将这个元素插入到 DOM 中
如果你使用 jQuery,遵循jQuery 选择器最佳实践
要改变元素的样式,修改“class”属性是最高效的方式之一 。你要改变 DOM 树的层次越深,这一条就越高效(这也有助于将表现和逻辑分开) 。
尽可能的只对 position 为 absolute 或 fix 的元素做动画 。
当滚动时禁用一些复杂的 :hover 动画是一个很好的主意(例如,给 body 标签加一个 no-hover 的 class)关于这个主题的文章 。