移動端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,它會自動爲您批處理讀取和寫入,應當能防止您意外觸發強制同步佈局或佈局抖動。

相關文章
相關標籤/搜索