移动端h5动画交换类优化

避免大型、复杂的布局和布局抖动

布局是浏览器计算各元素几何信息的过程:元素的大小以及在页面中的位置。 根据所用的 CSS、元素的内容或父级元素,每一个元素都将有显式或隐含的大小信息。此过程在 Chrome、Opera、Safari 和 Internet Explorer 中称为布局 (Layout)。 在 Firefox 中称为自动重排 (Reflow),但实际上其过程是同样的。css

与样式计算类似,布局开销的直接考虑因素以下:git

  1. 须要布局的元素数量。
  2. 这些布局的复杂性。
  • 布局的做用范围通常为整个文档。
  • DOM 元素的数量将影响性能;应尽量避免触发布局。
  • 评估布局模型的性能;新版 Flexbox 通常比旧版 Flexbox 或基于浮动的布局模型更快。
  • 避免强制同步布局和布局抖动;先读取样式值,而后进行样式更改。

尽量避免布局操做

当您更改样式时,浏览器会检查任何更改是否须要计算布局,以及是否须要更新渲染树。对“几何属性”(如宽度、高度、左侧或顶部)的更改都须要布局计算。github

.box {  width: 20px;  height: 20px;}/** * Changing width and height * triggers layout. */.box--expanded {  width: 200px;  height: 350px;}

布局几乎老是做用到整个文档。若是有大量元素,将须要很长时间来算出全部元素的位置和尺寸。web

若是没法避免布局,关键仍是要使用 Chrome DevTools 来查看布局要花多长时间,并肯定布局是否为形成瓶颈的缘由。首先,打开 DevTools,选择“Timeline”标签,点击“record”按钮,而后与您的网站交互。当您中止记录时,将看到网站表现状况的详细分析:浏览器

DevTools 显示布局要较长时间

在仔细研究上例中的框架时,咱们看到超过 20 毫秒用在布局上,当咱们在动画中设置 16 毫秒来获取屏幕上的框架时,此布局时间太长。您还能够看到,DevTools 将说明树的大小(本例中为 1618 个元素)以及须要布局的节点数。安全

Note:想要一个有关哪些 CSS 属性会触发布局、绘制或合成的确切列表?请查看CSS 触发器框架

使用 flexbox 而不是较早的布局模型

网页有各类布局模型,一些模式比其余模式受到更普遍的支持。最先的 CSS 布局模型使咱们可以在屏幕上对元素进行相对、绝对定位或经过浮动元素定位。dom

下面的屏幕截图显示了在 1,300 个框上使用浮动的布局开销。固然,这是一我的为的例子,由于大多数应用将使用各类手段来定位元素。函数

使用浮动做为布局

若是咱们更新此示例以使用 Flexbox(Web 平台的新模型),则出现不一样的状况:布局

使用 flexbox 做为布局

如今,对于相同数量的元素和相同的视觉外观,布局的时间要少得多(本例中为分别 3.5 毫秒和 14 毫秒)。务必记住,对于某些状况,可能没法选择 Flexbox,由于它没有浮动那么受支持,可是在可能的状况下,至少应研究布局模型对网站性能的影响,而且采用最大程度减小网页执行开销的模型。

在任何状况下,不论是否选择 Flexbox,都应当在应用的高压力点期间尝试彻底避免触发布局

避免强制同步布局

将一帧送到屏幕会采用以下顺序:

使用 flexbox 做为布局

首先 JavaScript 运行,而后计算样式,而后布局。可是,可使用 JavaScript 强制浏览器提早执行布局。这被称为强制同步布局

要记住的第一件事是,在 JavaScript 运行时,来自上一帧的全部旧布局值是已知的,而且可供您查询。所以,若是(例如)您要在帧的开头写出一个元素(让咱们称其为“框”)的高度,可能编写一些以下代码:

// Schedule our function to run at the start of the frame.requestAnimationFrame(logBoxHeight);function logBoxHeight() {  // Gets the height of the box in pixels and logs it out.  console.log(box.offsetHeight);}

若是在请求此框的高度以前,已更改其样式,就会出现问题:

function logBoxHeight() {  box.classList.add('super-big');  // Gets the height of the box in pixels  // and logs it out.  console.log(box.offsetHeight);}

如今,为了回答高度问题,浏览器必须先应用样式更改(因为增长了super-big类),而后运行布局。这时它才能返回正确的高度。这是没必要要的,而且多是开销很大的工做。

所以,始终应先批量读取样式并执行(浏览器可使用上一帧的布局值),而后执行任何写操做:

正确完成时,以上函数应为:

function logBoxHeight() {  // Gets the height of the box in pixels  // and logs it out.  console.log(box.offsetHeight);  box.classList.add('super-big');}

大部分状况下,并不须要应用样式而后查询值;使用上一帧的值就足够了。与浏览器同步(或比其提早)运行样式计算和布局可能成为瓶颈,而且您通常不想作这种设计。

避免布局抖动

有一种方式会使强制同步布局甚至更糟:连续不断地执行大量这种布局。看看这个代码:

function resizeAllParagraphsToMatchBlockWidth() {  // Puts the browser into a read-write-read-write cycle.  for (var i = 0; i < paragraphs.length; i++) {    paragraphs[i].style.width = box.offsetWidth + 'px';  }}

此代码循环处理一组段落,并设置每一个段落的宽度以匹配一个称为“box”的元素的宽度。这看起来没有害处,但问题是循环的每次迭代读取一个样式值 (box.offsetWidth),而后当即使用此值来更新段落的宽度 (paragraphs[i].style.width)。在循环的下次迭代时,浏览器必须考虑样式已更改这一事实,由于offsetWidth是上次请求的(在上一次迭代中),所以它必须应用样式更改,而后运行布局。每次迭代都将出现此问题!

此示例的修正方法仍是先读取值,而后写入值:

// Read.var width = box.offsetWidth;function resizeAllParagraphsToMatchBlockWidth() {  for (var i = 0; i < paragraphs.length; i++) {    // Now write.    paragraphs[i].style.width = width + 'px';  }}

若是要保证安全,应当查看FastDOM,它会自动为您批处理读取和写入,应当能防止您意外触发强制同步布局或布局抖动。

相关文章
相关标签/搜索