瀏覽器層合成與頁面性能優化

頁面展現

在編寫頁面中,咱們要知道瀏覽器如何處理 HTMLJavaScriptCSS
須要瞭解並注意五個主要區域, 這些咱們擁有控制權的部分,也是像素至屏幕管道中的關鍵點。css

image

每一步簡介

  • JavaScript。 通常來講,咱們會使用 JavaScript 來實現一些視覺變化的效果。好比用 jQuery 的 animate 函數作一個動畫、對一個數據集進行排序或者往頁面裏添加一些 DOM 元素等。固然,除了 JavaScript,還有其餘一些經常使用方法也能夠實現視覺變化效果,好比:CSS Animations、Transitions 和 Web Animation API。
  • 樣式計算。 此過程是根據匹配選擇器(例如 .headline 或 .nav > .nav__item)計算出哪些元素應用哪些 CSS 規則的過程。從中知道規則以後,將應用規則並計算每一個元素的最終樣式。
  • 佈局。 在知道對一個元素應用哪些規則以後,瀏覽器便可開始計算它要佔據的空間大小及其在屏幕的位置。網頁的佈局模式意味着一個元素可能影響其餘元素,例如 <body> 元素的寬度通常會影響其子元素的寬度以及樹中各處的節點,所以對於瀏覽器來講,佈局過程是常常發生的。
  • 繪製。 繪製是填充像素的過程。它涉及繪出文本、顏色、圖像、邊框和陰影,基本上包括元素的每一個可視部分。繪製通常是在多個表面(一般稱爲層)上完成的。
  • 合成。 因爲頁面的各部分可能被繪製到多層,由此它們須要按正確順序繪製到屏幕上,以便正確渲染頁面。對於與另外一元素重疊的元素來講,這點特別重要,由於一個錯誤可能使一個元素錯誤地出如今另外一個元素的上層。

ps: 固然,不是每一步更改都會遵循上圖這個流程。前端

每一步不是必經的

好比:git

  • 更改了元素的佈局相關的屬性:width, height, 位置... 那麼瀏覽器就會檢查其餘元素,自動 重排一次
  • 更改了元素的 color, 陰影... 不會影響頁面的佈局,那麼瀏覽器就會跳過佈局。這就是咱們日常說的:重排必定引發重繪,重繪不必定引發重排
  • 若是更改了 一個既不會佈局,也不會繪製的屬性,那麼瀏覽器直接跳到最後一步,不得不說,這是最高效的

使用 csstriggers 能夠詳細看到 css 屬性改變時觸發的流程。github

如何提高繪製的性能

儘可能使用影響較少的屬性

舉個🌰:web

<div class="box box1">1</div>
<div class="box box2"> 2 </div>
  <script>
  const box1 = document.querySelector('.box1');
  setTimeout(() => {
     box1.style.display = 'none'
  }, 3000);
  </script>

relayout

咱們能夠看到,box1box2 都綠(重繪)了一次,說明 box1 的變化影響了 box2。那這個屬性變化的代價是比較大的。瀏覽器

假如是我讓 box1 的位置 向右移動 60px,咱們作以下更改:性能優化

box1.style.display = 'none'

leftrepaint

如今 box2的位置不受影響,直觀地看到 box2是沒被綠(重繪)的。微信

提高爲合成層(Compositing Layers)

咱們在上一步作了優化,box2 已經不受影響,可是 box1 依然被重繪,那能不能在優化呢。
答案是能的。
left 這個屬性的改變會形成的影響是:前端性能

layout -> painted -> composited

這個流程能夠在 csstriggers 看到。
image
那如今咱們要找到一個 css 屬性,既能讓元素位移,又能形成的影響最小。
答案是有的:
transform:影響最小,直接到達最後一步 compositor
作以下更改:ide

box1.style.transform = 'translateX(60px)'

transform-normal

好像事與願違。box1, box2 都被重繪了。
這裏由於:他們都在一個層上,一個元素的變化也影響了其餘元素的變化。瀏覽器會聯合須要繪製的區域,而致使整個屏幕重繪
其實這裏有個條件:
更改屬性所在的元素應處於其自身的合成層,若是沒在,咱們能夠提高爲合成層
這樣就不會影響其餘元素,而能減小繪製區域。

提高爲合成層的緣由有一下幾種

這裏我大概羅列了這麼多

  • video
  • 有 3D transform
  • backface-visibility 爲 hidden
  • 對 opacity、transform、fliter、backdropfilter 應用了 animation 或者 transition(須要是 active 的 animation 或者 transition,當 animation 或者 transition 效果未開始或結束後,提高合成層也會失效)
  • will-change 設置爲 opacity、transform、top、left、bottom、right(其中 top、left 等須要設置明確的定位屬性,如 relative 等)
  • 重疊緣由

box1 上面作以下更改:

will-change: transform;

再次觀察效果:

transform-layer

大功告成:

  • box1 不在重繪了
  • box2 不受影響

咱們能夠查看最終的分層效果:

image

ps 裏面的圖層差很少,每個圖層疊加在一塊兒組成咱們看到的網頁。

物極必反

圖層越多越好嗎?
固然不是。提高合成層也得 消耗額外的內存和管理資源

正如MDN所說:若是你的頁面在性能方面沒什麼問題,則不要添加 will-change 屬性來榨取一丁點的速度。 will-change 的設計初衷是做爲最後的優化手段,用來嘗試解決現有的性能問題

參考

前端性能優化之 Composite
關鍵轉譯路徑 Critical Rendering Path
will-change
堅持僅合成器的屬性和管理層計數

最後

若是喜歡本篇文章,能夠關注的微信公衆號,若是不嫌煩,還能夠把它添加到桌面😀。

相關文章
相關標籤/搜索