瀏覽器渲染性能優化

来源:http://www.cnblogs.com/kevin2chen/archive/2017/06/18/7045002.html
-Advertisement-
Play Games

渲染性能 頁面不僅要快速載入,而且要順暢地運行;滾動應與手指的滑動一樣快,並且動畫和交互應如絲綢般順滑。 60fps 與設備刷新率 60fps 與設備刷新率 目前大多數設備的屏幕刷新率為 60 次/秒。因此,如果在頁面中有一個動畫或漸變效果,或者用戶正在滾動頁面,那麼瀏覽器渲染動畫或頁面的每一幀的速 ...


渲染性能

頁面不僅要快速載入,而且要順暢地運行;滾動應與手指的滑動一樣快,並且動畫和交互應如絲綢般順滑。

60fps 與設備刷新率

目前大多數設備的屏幕刷新率為 60 /。因此,如果在頁面中有一個動畫或漸變效果,或者用戶正在滾動頁面,那麼瀏覽器渲染動畫或頁面的每一幀的速率也需要跟設備屏幕的刷新率保持一致。

其中每個幀的預算時間僅比 16 毫秒多一點 (1 秒/ 60 = 16.66 毫秒)。但實際上,瀏覽器有整理工作要做,因此所有工作需要在 10 毫秒內完成。如果無法符合此預算,幀率將下降,並且內容會在屏幕上抖動(judders)。此現象通常稱為卡頓(jank,會對用戶體驗產生負面影響。

像素管道(The pixel pipeline)

在工作時需要瞭解並註意五個主要區域,這些是擁有最大控制權的部分,也是像素至屏幕管道中的關鍵點:

 

  • JavaScript。一般來說,會使用 JavaScript 來實現一些視覺變化的效果。比如用 jQuery 的 animate 函數做一個動畫、對一個數據集進行排序或者往頁面里添加一些 DOM 元素等。除了 JavaScript,還有其他一些常用方法也可以實現視覺變化效果,比如:CSS Animations、Transitions 和 Web Animation API。
  • 樣式計算Sytle calculations。This is the process of figuring out which CSS rules apply to which elements based on matching selectors, for example, .headline or .nav > .nav__item. From there, once rules are known, they are applied and the final styles for each element are calculated.
  • 佈局。在知道對一個元素應用哪些規則之後,瀏覽器即可開始計算它要占據的空間大小及其在屏幕的位置。網頁的佈局模式意味著一個元素可能影響其他元素,例如 <body> 元素的寬度一般會影響其子元素的寬度以及樹中各處的節點,因此對於瀏覽器來說,佈局過程是經常發生的。
  • 繪製。繪製是填充像素的過程。它涉及繪出文本、顏色、圖像、邊框和陰影,包括元素的每個可視部分。繪製一般是在多個錶面(通常稱為層layers)上完成的。
  • 合成。由於頁面的各部分可能被繪製到多層,由此它們需要按正確順序繪製到屏幕上,以便正確渲染頁面。對於與另一元素重疊的元素來說,這點特別重要,因為一個錯誤可能使一個元素錯誤地出現在另一個元素的上層。

管道的每個部分都有機會產生卡頓,因此務必準確瞭解代碼觸發管道的哪些部分。

不一定每幀都總是會經過管道每個部分的處理。實際上,不管是使用 JavaScript、CSS 還是網路動畫,在實現視覺變化時,管道針對指定幀的運行通常有三種方式:

1. JS / CSS > 樣式 > 佈局 > 繪製 > 合成

 

如果修改元素的“layout”屬性,即改變了元素的幾何屬性(例如寬度、高度等),那麼瀏覽器將必須檢查所有其他元素,然後“自動重排”頁面(reflow the page)。任何受影響的部分都需要重新繪製,而且最終繪製的元素需進行合成。

2. JS / CSS > 樣式 > 繪製 > 合成

 

如果修改“paint only”屬性(例如背景圖片、文字顏色或陰影等),即不會影響頁面佈局的屬性,則瀏覽器會跳過佈局,但仍將執行繪製。

3. JS / CSS > 樣式 > 合成

 

如果更改一個既不用重新佈局也不要重新繪製的屬性,則瀏覽器將只執行合成。這個最後的方式開銷最小,最適合於應用生命周期中的高壓力點,例如動畫或滾動。

性能是一種避免執行的藝術,並且使執行的任何操作儘可能高效。 許多情況下,這需要與瀏覽器配合,而不是跟它對著乾。 值得謹記的是,上面列出的各項管道工作在計算開銷上有所不同,一些任務比其他任務的開銷要大!

優化 JavaScript 執行

JavaScript often triggers visual changes. Sometimes that's directly through style manipulations, and sometimes it's calculations that result in visual changes, like searching or sorting data.時機不當或長時間運行的 JavaScript 可能是導致性能問題的常見原因,應當設法儘可能減少其影響。

JavaScript 性能分析可以說是一門藝術,因為編寫的 JavaScript 代碼與實際執行的代碼完全不像。現代瀏覽器使用 JIT 編譯器和各種各樣的優化和技巧來實現儘可能快的執行,這極大地改變了代碼的動態性。

一些幫助應用很好地執行 JavaScript的事情:

  • 對於動畫效果的實現,避免使用 setTimeout 或 setInterval,使用 requestAnimationFrame。
  • 將長時間運行的 JavaScript 從主線程移到 Web Worker。
  • 使用小任務來執行對多個幀的 DOM 更改。
  • 使用 Chrome DevTools 的 Timeline 和 JavaScript 分析器來評估 JavaScript 的影響。

使用 requestAnimationFrame 來實現視覺變化

當屏幕正在發生視覺變化時,最好在幀的開頭執行操作。保證 JavaScript 在幀開始時運行的唯一方式是使用 requestAnimationFrame。

/**
 * If run as a requestAnimationFrame callback, this
 * will be run at the start of the frame.
 */
function updateScreen(time) {
  // Make visual updates here.
}
requestAnimationFrame(updateScreen);

框架或示例可能使用 setTimeout 或 setInterval 來執行動畫之類的視覺變化,但這種做法的問題是,回調函數在幀中的某個時點運行,可能剛好在幀的末尾,而這經常會使我們丟失幀,導致卡頓。(composite等js的運行需要時間,會阻塞UI更新)。

 

事實上,jQuery 目前的預設 animate 行為是使用 setTimeout!強烈建議打上補丁程式以使用 requestAnimationFrame

降低複雜性或使用 Web Worker

JavaScript 在瀏覽器的主線程上運行,恰好與樣式計算、佈局以及許多情況下的繪製一起運行。如果 JavaScript 運行時間過長,就會阻塞這些其他工作,可能導致幀丟失。

因此,要妥善處理 JavaScript 何時運行以及運行多久。例如,如果在滾動之類的動畫中,最好是想辦法使 JavaScript 保持在 3-4 毫秒的範圍內。超過此範圍,就可能要占用太多時間。如果在空閑期間,則可以不必那麼斤斤計較所占的時間。

在許多情況下,可以將純計算工作移到 Web Worker,例如,不需要 DOM 訪問許可權,數據操作或遍歷(例如排序或搜索),往往很適合這種模型,載入和模型生成也是如此。

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
   var sortedData = evt.data;
   // Update data on screen...
});

並非所有工作都適合此模型:Web Worker 沒有 DOM 訪問許可權。如果操作必須在主線程上執行,可以考慮一種批量方法,將大型任務分割為小任務,每個小任務所占時間不超過幾毫秒,並且在每幀的 requestAnimationFrame 處理程式內運行。

var taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);
function processTaskList(taskStartTime) {
  var taskFinishTime;
  do {
    // Assume the next task is pushed onto a stack.
    var nextTask = taskList.pop();
    // Process nextTask.
    processTask(nextTask);
    // Go again if there’s enough time to do the next task.
    taskFinishTime = window.performance.now();
  } while (taskFinishTime - taskStartTime < 3);
  if (taskList.length > 0)
    requestAnimationFrame(processTaskList);
}

此方法會產生 UX 和 UI 後果,您將需要使用進度或活動指示器來確保用戶知道任務正在被處理。在任何情況下,此方法都不會占用應用的主線程,從而有助於主線程始終對用戶交互作出快速響應。

瞭解 JavaScript 的“frame tax”

在評估一個框架、庫或自己的代碼時,務必逐幀評估運行 JavaScript 代碼的開銷。當執行性能關鍵的動畫工作(例如變換或滾動)時,這點尤其重要。

測量 JavaScript 開銷和性能情況的最佳方法是使用 Chrome DevTools。通常,您將獲得如下的簡單記錄:

 

The Main section provides a flame chart of JavaScript calls so you can analyze exactly which functions were called and how long each took.

如果發現有長時間運行的 JavaScript,則可以在 DevTools 用戶界面的頂部啟用 JavaScript 分析器:

 


以這種方式分析 JavaScript 會產生開銷,因此一定只在想要更深入瞭解 JavaScript 運行時特性時才啟用它。啟用此覆選框後,現在可以執行相同的操作,您將獲得有關 JavaScript 中調用了哪些函數的更多信息:

 

有了這些信息之後,就可以評估 JavaScript 對應用性能的影響,並開始找出和修正函數運行時間過長的熱點(hotspots)。如前所述,應當設法移除長時間運行的 JavaScript,或者若不能移除,則將其移到 Web Worker 中,騰出主線程繼續執行其他任務。

避免微優化 JavaScript

知道瀏覽器執行一個函數版本比另一個函數要快 100 倍可能會很酷,比如請求元素的offsetTop比計算getBoundingClientRect()要快,但是,您在每幀調用這類函數的次數幾乎總是很少。因此,把重點放在 JavaScript 性能的這個方面通常是白費勁。您一般只能節省零點幾毫秒的時間。

如果您開發的是游戲或計算開銷很大的應用,則可能屬於本指南的例外情況,因為您一般會將大量計算放入單個幀,在這種情況下各種方法都很有用。

簡而言之,慎用微優化,因為它們通常不會映射到您正在構建的應用類型。2/8法則,先從瓶頸處著手優化。

縮小樣式計算的範圍並降低其複雜性

通過添加和刪除元素,更改屬性、類或通過動畫來更改 DOM,都會導致瀏覽器重新計算元素樣式,在很多情況下還會對頁面或頁面的一部分進行佈局(即自動重排)。This process is called computed style calculation.

計算樣式的第一部分是創建一組匹配選擇器,這實質上是瀏覽器計算出給指定元素應用哪些classes, pseudo-selectors and IDs。

第二部分涉及從匹配選擇器中獲取所有樣式規則,並計算出此元素的最終樣式。在 Blink(Chrome 和 Opera 的渲染引擎)中,這些過程的開銷至少在目前是大致相同的:

Roughly 50% of the time used to calculate the computed style for an element is used to match selectors,而另一半時間用於從匹配的規則中構建 RenderStyle(computed style representation)。

  • 降低選擇器的複雜性;使用以類為中心的方法,例如 BEM規範(Block-Element_Modifer)。
  • 減少必須計算其樣式的元素數量。

降低選擇器的複雜性

在最簡單的情況下,在 CSS 中只有一個類的元素:

.title {
  /* styles */
}

但是,隨著項目的增長,將可能產生更複雜的 CSS,最終的選擇器可能變成這樣:

.box:nth-last-child(-n+1) .title {
  /* styles */
}

為了知道是否需要應用樣式,瀏覽器實際上必須詢問“這是否為有 title 類的元素,其父元素恰好是負第 N 個子元素加上 1 個帶 box 類的元素?”計算此結果可能需要大量時間,具體取決於所用的選擇器和相應的瀏覽器。特定的選擇器可以更改為一個類:

.final-box-title {
  /* styles */
}

開發者可能對該類的名稱有疑問,但此工作對於瀏覽器而言要簡單得多。在上一版本中,為了知道該元素是否為其類型的最後一個,瀏覽器首先必須知道關於其他元素的所有情況,以及其後面是否有任何元素會是第 N 個最後子元素,這比簡單地將類選擇器與元素匹配的開銷要大得多。

生成render tree時,對於每個DOM元素,必須在所有Style Rules中找到符合的 selector 並將對應的樣式規則進行合併。
css選擇器的解析是從右往左的,這樣公共樣式就在CSSOM樹的父節點上,更具體的樣式(選擇器更具體)會在子節點上,節點分支和遍歷次數都會變少。如果採用 left-to-right 的方式讀取css規則,那麼大多數規則讀到最後才會發現是不匹配,做了很多無用功;而採取 right-to-left 的方式,只要發現最右邊選擇器不匹配,就直接捨棄,避免很多無效匹配。

減少要計算樣式的元素數量

另一個性能考慮,在元素更改時需要計算的工作量對於許多樣式更新而言是更重要的因素。

In general terms, the worst case cost of calculating the computed style of elements is the number of elements multiplied by the selector count, because each element needs to be at least checked once against every style rule to see if it matches.

註:以前曾經是這樣:如果改變了(例如)body 元素上的一個類,則該頁的所有子元素將需要重新計算其計算樣式。現在有點不一樣:對於更改時會導致重新計算樣式的元素,某些瀏覽器維護一小組每個這種元素獨有的規則。這意味著,根據元素在樹中的位置以及所改變的具體屬性,元素不一定需要重新計算。

樣式計算可能經常是直接針對少量目標元素,而不是聲明整個頁面無效。在現代瀏覽器中,這往往不再是個問題,因為瀏覽器並不一定需要檢查一項更改可能影響的所有元素。另一方面,較早的瀏覽器不一定針對此類任務進行了優化。應當儘可能減少聲明為無效的元素的數量

註:如果您熱衷於網頁組件,有一點值得註意,樣式計算在這方面稍有不同,因為預設情況下樣式不會跨越 Shadow DOM 的邊界,並且範圍限於單個組件,而不是整個樹。但是,總體來看,同樣的概念仍然適用:規則簡單的小樹比規則複雜的大樹會得到更高效地處理。

測量樣式重新計算的開銷

測量樣式重新計算的最簡單、最好的方法是使用 Chrome DevTools 的 Timeline 模式。首先,打開 DevTools,轉至 Timeline 選項卡,選中記錄並與您的網站交互。停止記錄後,將看到下圖所示情況。

 

頂部的條表示每秒幀數,如果看到柱形超過較低的線,即 60fps 線,則存在長時間運行的幀。

 

如果一些滾動之類的交互或其他交互時出現長時間運行的幀,則應當進一步審查。

如果出現較大的紫色塊,如上例所示,請點擊記錄瞭解到更多細節。

 

 

在這次抓取中,有一個長時間運行的重新計算樣式事件,其時間剛好超過 18 毫秒,並且恰好發生在滾動期間,導致用戶體驗到明顯的抖動。

如果點擊事件本身,將看到一個調用棧,精確指出了您的 JavaScript 中導致觸發樣式更改的位置。此外,還獲得樣式受更改影響的元素數量(本例中剛好超過 400 個元素),以及執行樣式計算所花的時間。您可以使用此信息來開始嘗試在代碼中查找修正點。

使用BEM規範

BEM的編碼方法實際上納入了上述選擇器匹配的性能優勢,因為它建議所有元素都有單個類,並且在需要層次結構時也納入了類的名稱:

.list { }
.list__list-item { }

如果需要一些修飾符,像在上面我們想為最後一個子元素做一些特別的東西,就可以按如下方式添加:

.list__list-item--last-child {}

如果您在尋找一種好方法來組織您的 CSS,則 BEM 真的是個很好的起點,不僅從結構的角度如此,還因為樣式查找得到了簡化。

避免大型、複雜的佈局和佈局抖動

佈局是瀏覽器計算各元素幾何信息的過程:元素的大小以及在頁面中的位置。 根據所用的 CSS、元素的內容或父級元素,每個元素都將有顯式或隱含的大小信息。此過程在 Chrome、Opera、Safari 和 Internet Explorer 中稱為佈局 (Layout)。 在 Firefox 中稱為自動重排 (Reflow),但實際上其過程是一樣的。

與樣式計算相似,佈局開銷的直接考慮因素如下:

  1. 需要佈局的元素數量。
  2. 這些佈局的複雜性。
  • 佈局的作用範圍一般為整個文檔。
  • DOM 元素的數量將影響性能,應儘可能避免觸發佈局。
  • 評估佈局模型的性能;新版 Flexbox比舊版 Flexbox 或基於浮動的佈局模型更快。
  • Avoid forced synchronous layouts and layout thrashing; read style values then make style changes.

儘可能避免佈局操作

當更改樣式時,瀏覽器會檢查更改是否需要計算佈局,以及是否需要更新渲染樹。幾何屬性(如寬度、高度、左側或頂部)的更改都需要佈局計算。

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

佈局幾乎總是作用到整個文檔。 如果有大量元素,將需要很長時間來算出所有元素的位置和尺寸。

如果無法避免佈局,關鍵還是要使用 Chrome DevTools 來查看佈局要花多長時間,並確定佈局是否是造成瓶頸的原因。首先,打開 DevTools,選擇“Timeline”標簽,點擊“record”按鈕,然後與您的網站交互。當您停止記錄時,將看到網站表現情況的詳細分析:

 

在仔細研究上例中的框架時,我們看到超過 20 毫秒用在佈局上,當我們在動畫中設置 16 毫秒來獲取屏幕上的幀時,此佈局時間太長。您還可以看到,DevTools 將說明樹的大小(本例中為 1618 個元素)以及需要佈局的節點數。

使用 flexbox 而不是較早的佈局模型

網頁有各種佈局模型,一些模式比其他模式受到更廣泛的支持。最早的 CSS 佈局模型使我們能夠在屏幕上對元素進行相對、絕對定位或通過浮動元素定位。

下麵的屏幕截圖顯示了在 1,300 個框上使用浮動的佈局開銷。當然,這是一個人為的例子,因為大多數應用將使用各種手段來定位元素。

 

 

如果我們更新此示例以使用 Flexbox(Web 平臺的新模型),則出現不同的情況:

 

現在,對於相同數量的元素和相同的視覺外觀,佈局的時間要少得多(本例中為分別 3.5 毫秒和 14 毫秒)。務必記住,對於某些情況,可能無法選擇 Flexbox,因為它沒有浮動那麼受支持,但是在可能的情況下,至少應研究佈局模型對網站性能的影響,並且採用最大程度減少網頁執行開銷的模型。

在任何情況下,不管是否選擇 Flexbox,都應當在應用的高壓力點期間嘗試完全避免觸發佈局

避免強制同步佈局

將一幀送到屏幕會採用如下順序:

 

首先 JavaScript 運行,然後計算樣式,然後佈局。但是,JavaScript 在更改元素樣式後,獲取其幾何屬性的值,此時會強制瀏覽器應用新樣式提前執行佈局,值後才能獲取幾何屬性值。這被稱為強制同步佈局(forced synchronous layout

要記住的第一件事是,在 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');
}

大部分情況下,並不需要先應用新樣式然後查詢值,使用上一幀的值就足夠了。與瀏覽器同步(或比其提前)運行樣式計算和佈局可能成為瓶頸。

避免佈局超負荷(thrashing)

有一種方式會使強制同步佈局更糟:連續執行大量這種強制佈局。如下:

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

簡化繪製的複雜度、減小繪製區域

繪製是填充像素的過程,像素最終合成到用戶的屏幕上。 它往往是管道中運行時間最長的任務,應儘可能避免此任務。

  • 除 transform 或 opacity 屬性之外,更改任何屬性始終都會觸發繪製。
  • 繪製通常是像素管道中開銷最大的部分,應儘可能避免繪製。
  • 通過layer promotion和動畫的編排來減少繪製區域。
  • 使用 Chrome DevTools paint profile來評估繪製的複雜性和開銷;應儘可能降低複雜性並減少開銷。

觸發佈局與繪製

如果觸發佈局,則總是會觸發繪製,因為更改任何元素的幾何屬性意味著其像素需要修正!

 

如果更改非幾何屬性,例如背景、文本或陰影,也可能觸發繪製。在這些情況下,不需要佈局,並且管道將如下所示:

 

使用 Chrome DevTools 快速確定繪製瓶頸

 

您可以使用 Chrome DevTools 來快速確定正在繪製的區域。打開 DevTools,按下鍵盤上的 Esc 鍵。在出現的面板中,轉到“rendering”標簽,然後選中“Show paint rectangles”。

打開此選項後,每次發生繪製時,Chrome 將讓屏幕閃爍綠色。如果看到整個屏幕閃爍綠色,或看到不應繪製的屏幕區域,則應當進一步研究。

 

Chrome DevTools Timeline 中有一個選項提供更多信息:繪製分析器。要啟用此選項,轉至 Timeline,然後選中頂部的“Paint”框。需要註意的是,請務必僅在嘗試分析繪製問題時才打開此選項,因為它會產生開銷,並且會影響性能分析結果。最好是在想要更深入瞭解具體繪製內容時使用。

 

完成了上述設置之後,現在可以運行 Timeline 錄製,並且繪製記錄將包含更多的細節。通過點擊一幀的繪製記錄,您將進入該幀的繪製分析器:

點擊繪製分析器將調出一個視圖,您可以查看所繪製的元素、所花的時間,以及所需的各個繪製調用:

 

此分析器顯示區域和複雜性(實際上就是繪製所花的時間),如果不能選擇避免繪製,這兩個都是可以設法修正的方面。

提升移動或淡出的元素

繪製並非總是繪製到記憶體中的單個圖像。事實上,在必要時瀏覽器可以繪製到多個圖像或合成層(compositor layers)。

 

此方法的優點是,定期重繪的或通過變形在屏幕上移動的元素,可以在不影響其他元素的情況下進行處理。Sketch、GIMP 或 Photoshop 之類的藝術文件也是如此,各個層可以在彼此的上面處理併合成,以創建最終圖像。

創建新層的最佳方式是使用 will-change CSS 屬性。此方法在 Chrome、Opera 和 Firefox 上有效,並且通過 transform 的值將創建一個新的合成器層:

.moving-element {
  will-change: transform;
}

對於不支持 will-change 但受益於層創建的瀏覽器,例如 Safari 和 Mobile Safari,需要使用3D 變形來強制創建一個新層:

.moving-element {
  transform: translateZ(0);
}

但需要註意的是:不要創建太多層,因為每層都需要記憶體和管理開銷。

如果已將一個元素提升到一個新層,可使用 DevTools 確認這樣做已帶來性能優勢。請勿在不分析的情況下提升元素。

減少繪製區域

然而有時,雖然提升元素,卻仍需要繪製工作。繪製問題的一個大挑戰是,瀏覽器將兩個需要繪製的區域聯合在一起,而這可能導致整個屏幕重繪。因此,如果頁面頂層有一個固定標頭,而在屏幕底部還有正在繪製的元素,則整個屏幕可能最終要重繪。

減少繪製區域往往是編排動畫和變換,使其不過多重疊,或設法避免對頁面的某些部分設置動畫。

降低繪製的複雜性

 

在談到繪製時,一些繪製比其他繪製的開銷更大。例如,繪製任何涉及模糊(例如陰影)的元素所花的時間將比(例如)繪製一個紅框的時間要長。但是,對於 CSS 而言,這點並不總是很明顯:background: red; 和 box-shadow: 0, 4px, 4px, rgba(0,0,0,0.5); 看起來不一定有截然不同的性能特性,但確實很不相同。

利用上述繪製分析器,您可以確定是否需要尋求其他方式來實現效果。問問自己,是否可能使用一組開銷更小的樣式或替代方式來實現最終結果。

您要儘可能的避免繪製的發生,特別是在動畫效果中。因為每幀 10 毫秒的時間預算一般來說是不足以完成繪製工作的,尤其是在移動設備上。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ES 2015/6 新增內容還是比較多的,這裡僅大綱性的列舉一下(不一定全面)這些特性。其實,每個點挖進去都會有很多學問在裡頭,本文旨在彙總,所以不對這些特性進行深層次的討論及研究。隨後有時間的話,在單獨寫幾篇博客對常用的點進行深挖,與大家進行深度交流。 ...
  • ::before與::after兩個偽元素其實是CSS3中的內容,然而實際上在CSS2中就已經有了這兩者的身影,只不過CSS2中是前面加一個冒號來表示(:before和:after)。今天主要講講這兩個偽元素該如何使用。 一、與普通元素一樣可以給其添加樣式 比如說我想在文字前面添加一個圖標,如果我用 ...
  • 本文提到的網站性能指網站的響應速度,這也符合絕大部分人對於網站性能的理解:訪問快速的網站性能好,反之,訪問速度越慢,則網站性能越差。本文總結的優化方法是巨集觀的工程層面的方法,並不包含微觀的語言語法層面的方法,例如,JS、CSS的語法優化,這一部分同樣影響網站的性能,但語言語法層面的優化更多的是取決於 ...
  • 雖然時間軸早已不是什麼新鮮事物了,個人只是感興趣所以就研究一下,最近從網上搜索了一個個人感覺比較好的時間軸demo,下載下來研究了一下並做了下修改.具體的效果如下圖:(該demo實現的是滾動載入圖片) 代碼地址:http://files.cnblogs.com/files/cby-love/html ...
  • Canvas繪圖環境中有些屬於立即繪製圖形方法,有些繪圖方法是基於路徑的。 立即繪製圖形方法僅有兩個strokeRect(),fillRect(),雖然strokezText(),fillText()方法也是立即繪製的,但是文本不算是圖形。 基於路徑的繪製系統 大多數繪製系統,如:SVG(Scala ...
  • string對象 string對象的兩種創建 var a="hello"; var b=new String("hello"); //下麵是方法 //charAt()根據下標 找字元串中的字元 alert(a.charAt(3));//根據下標返回字元串某個字元 alert(a.charAt(10) ...
  • web存儲分類 客戶端和服務端 認識web存儲 隨著web應用的發展,是的客戶端存儲的用途越來越多,然而實現客戶端端存儲的方式也是越來越多樣化。最簡單最相容的方式就是cookie,但作為真正的客戶端存儲cookie還是存在著許許多多的弊端的。同時,各種瀏覽器也有屬於自己的存儲方式。例如,IE6以及以 ...
  • 問題:js這麼語言的能力取決於什麼?(運行平臺) 答:現在的js語言可以在瀏覽器運行(js如果是在瀏覽器端運行則不能操作磁碟文件),也可以在伺服器端運行nodeJs(js在伺服器端能夠操作文件)。 問題:js是否能夠操作文件(一般不能),ajax能否操作文件(一般不能)? 答: a. js一般不能, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...