css relayout repaint致使ios下的bug

問題

近日在作移動端web時發現一個問題就是在ios中若是動畫元素使用了left top值時在微信易信客戶端中不能使用系統的複製文本功能了。糾結了許久,後來在大神的提醒下,瞭解到是由於css的repaint致使的。改用了css3的translate之後就OK了, 查了一下資料,發現有如下的一些知識點,如今貼出來,有須要的人能夠看看。參考資料:https://github.com/AlloyTeam/Mars/blob/master/performance/css-property-animation-performance.mdcss

原因

CSS動畫屬性會觸發整個頁面的重排relayout、重繪repaint、重組recomposite
Paint一般是其中最花費性能的,儘量避免使用觸發paint的CSS動畫屬性,這也是爲何咱們推薦在CSS動畫中使用webkit-transform: translateX(3em)的方案代替使用left: 3em,由於left會額外觸發layout與paint,而webkit-transform只觸發整個頁面composite
div {
-webkit-animation-duration: 5s;
-webkit-animation-name: move;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: #808080;
position: absolute;
}
@-webkit-keyframes move{ios

from {
    left: 100px;
}
to {
    left: 200px;
}

}
以下圖使用left將持續觸發頁面重繪,表現爲紅色邊框:css3

movegit

@-webkit-keyframes move{github

from {
    -webkit-transform: translateX(100px);
}
to {
    -webkit-transform: translateX(200px);
}

}web

以下圖使用-webkit-transform頁面只發生重組,表現爲橙色邊框:canvas

move2瀏覽器

CSS屬性在CSS動畫中行爲表微信

瀏覽器繪製 DOM 的過程是這樣子的:移動端web

獲取 DOM 並將其分割爲多個層(layer)
將每一個層獨立地繪製進位圖(bitmap)中
將層做爲紋理(texture)上傳至 GPU
複合(composite)多個層來生成最終的屏幕圖像。

left/top/margin 之類的屬性會影響到元素在文檔中的佈局,當對佈局(layout)進行動畫時,該元素的佈局改變可能會影響到其餘元素在文檔中的位置,就致使了全部被影響到的元素都要進行從新佈局[1],瀏覽器須要爲整個層進行重繪並從新上傳到 GPU,形成了極大的性能開銷。

transform 屬於合成屬性(composite property),對合成屬性進行 transition/animation 動畫將會建立一個合成層(composite layer),這使得被動畫元素在一個獨立的層中進行動畫。一般狀況下,瀏覽器會將一個層的內容先繪製進一個位圖中,而後再做爲紋理(texture)上傳到 GPU,只要該層的內容不發生改變,就不必進行重繪(repaint),瀏覽器會經過從新複合(recomposite)來造成一個新的幀[2]。

層創立的條件以下:

3D 或透視變換 CSS 屬性
使用加速視頻解碼的 <video> 元素
擁有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
複合插件(如 Flash)
進行 opacity/transform 動畫的元素
擁有加速 CSS filters 的元素
元素有一個包含複合層的後代節點(換句話說,就是一個元素擁有一個子元素,該子元素在本身的層裏)
元素有一個 z-index 較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上面渲染)

總結:

對佈局屬性進行動畫,瀏覽器須要爲每一幀進行重繪並上傳到 GPU 中
對合成屬性進行動畫,瀏覽器會爲元素建立一個獨立的複合層,當元素內容沒有發生改變,該層就不會被重繪,瀏覽器會經過從新複合來建立動畫幀

另外能夠參考http://csstriggers.com/ 裏面有各類屬性對頁面佈局,重繪,重排的影響關係。

相關文章
相關標籤/搜索