1. 程式人生 > >css 重排與重繪

css 重排與重繪

### css 重繪與重排 我們要知道當瀏覽器下載完頁面的所有資源後,就會開始解析原始碼。 HTML 會被解析成 DOM Tree,Css 則會被渲染成 CSSOM Tree,最後它們會附加到一起,形成渲染樹(Render Tree)。當渲染樹構建完成時,就會開始繪製頁面元素。 這時如果 DOM 發生更改或者元素的 css 幾何屬性發生變化,比如 width,height,position 定位等。那麼就會引發一次瀏覽器的重排/重繪過程,也就是瀏覽器會重新計算元素的幾何屬性,並重新構造渲染樹,這個過程叫做重排,完成重排後,要將重新構建的渲染樹渲染到螢幕上,這個過程就是“重繪”。 而如果是 css 的非幾何屬性更改,則只會引起重繪。所以說重排一定會引起重繪,而重繪不一定會引起重排。 #### 重排 既然重排的原理是根據因為幾何屬性發生了改變,那麼我們就能夠總結一下引起重排的操作: 1、頁面首次渲染 2、新增或刪除 Dom 的顯示與隱藏 3、元素相對於文件的定位改變 4、元素的大小尺寸改變 5、新增行內 style 樣式 6、瀏覽器視窗大小發生改變時 #### 重繪 重繪相對來說就簡單點了,比如顏色改變,背景圖片改變,陰影改變等,只要不影響元素本身相對於瀏覽器文件的位置只會觸發重繪。 #### 效能優化 操作 DOM 的成本是非常高的,而且如果不小心改掉元素的幾何屬性,就會觸發重排和重繪,這時就會影響使用者體驗。我們來看一個簡單的例子: ``` var box = document.getElementById('box'); // 獲取頁面一個子元素 box.margin = "15px"; // 重排+重繪 box.border = "1px solid red"; // 又是一次重排+重繪 box.backgroundColor = "red"; // 沒有尺寸變化,只重繪 box.fontSize = "16px"; // 重排+重繪 // 新的DOM節點 - 重排+重繪 document.body.appendChild(document.createTextNode('!!!!')); ``` 只改當前頁面中的子節點,可能影響不是很明顯,如果修改的節點多了或者修改了頁面的頂級節點屬性,那麼就會推動整個頁面的變化,程式碼是十分昂貴的。 因此,從效能優化角度,我們可以從以下幾個方面著手: 1) 瀏覽器本身的優化策略 瀏覽器會維護一個佇列,將所有引起重排和重繪的操作都放在這個佇列裡,當操作達到一定的數量或者時間間隔時,瀏覽器會批量執行來優化重排過程。這樣可以讓多次的重排重繪,變成一次。但是有的特殊 style 屬性會使這種優化失效,例如offsetTop,scrollTop,clientTop等屬性,這些屬性都是要實時返回給使用者的幾何屬性或者佈局屬性,因此瀏覽器需要立即執行,觸發重排返回正確的值。 2) 最小化重排和重繪 避免設定大量的 style 行內樣式。修改單個 DOM 節點的多條語句合併成一個語句來執行。 DOM 元素的動畫屬性最好設定為 absolute 或者 fixed 定位。 3) css 動畫和效能處理 減少 js 操作元素的樣式,使用修改 class 類名方式修改樣式。 開啟動畫的 GPU 加速,渲染計算交給 GPU 處理。 避免頻繁計算樣式,可以快取變數,並且在變數中工作。 可以使用 querySelectorAll() 獲取的靜態集合替代 getElementByXX() 獲取的動態集合。 #### 小結 雖然篇幅不長,但是感謝你看完了這篇文章,最後我來總結一下幾個點:
  • 重排一定會引起重繪,而重繪不一定會引起重排。
  • 會引起重排和重繪的條件
  • 怎樣進行效能優化(減少 DOM 操作、高效能 API 的使用、開啟硬體加速、減少 DOM 操作等)
  • 瀏覽器本身的優化策略