position: absolute;_前端性能优化--transform与position
上個(gè)星期去yy語(yǔ)音面試,就有一個(gè)這樣問(wèn)題: transform與position:absolute 有什么區(qū)別? 我回家后查資料發(fā)現(xiàn)這道題目其實(shí)不簡(jiǎn)單啊,涉及到重排、重繪、硬件加速等網(wǎng)頁(yè)優(yōu)化的知識(shí)。
首先看一個(gè)用top、left實(shí)現(xiàn)的動(dòng)畫(huà)效果
<style>html,body {width: 100%;height: 100%;}.ball-running {animation: run-around 4s infinite;width: 100px;height: 100px;background-color: red;position: absolute;}@keyframes run-around {0%: {top: 0;left: 0;}25% {top: 0;left: 200px;}50% {top: 200px;left: 200px;}75% {top: 200px;left: 0;}}</style> <body><div class="ball-running"></div></body>在運(yùn)行的時(shí)候,會(huì)隱約覺(jué)得動(dòng)畫(huà)的運(yùn)行并不流暢,動(dòng)畫(huà)有些停頓的感覺(jué)。這時(shí)因?yàn)閠op和left的改變會(huì)觸發(fā)瀏覽器的 reflow和 repaint 。然后整個(gè)動(dòng)畫(huà)過(guò)程都在不斷觸發(fā)瀏覽器的重新渲染,這個(gè)過(guò)程是很影響性能的。
下面是chrome 瀏覽器performance中的監(jiān)測(cè)到的數(shù)據(jù)。在 chrome的rendering面板中可以看到?jīng)]改變一次位置瀏覽器就要渲染一個(gè)。
然后我用transform 重寫(xiě)一下這個(gè)動(dòng)畫(huà)效果
<style>html,body {width: 100%;height: 100%;}.ball-running {animation: run-around2 4s infinite;width: 100px;height: 100px;background-color: red;position: absolute;}@keyframes run-around2 {0%: {transform: translate(0, 0);}25% {transform: translate(200px, 0);}50% {transform: translate(200px, 200px);}75% {transform: translate(0, 200px);}} </style><body><div class="ball-running"></div></body>這時(shí)候會(huì)發(fā)現(xiàn)整個(gè)動(dòng)畫(huà)效果流暢了很多,在動(dòng)畫(huà)移動(dòng)的過(guò)程中也沒(méi)有發(fā)生repaint和reflow。
下面是chrome 瀏覽器performance中的監(jiān)測(cè)到的數(shù)據(jù)。以及rendering面板。
那么,為什么 transform 沒(méi)有觸發(fā) repaint 呢?原因就是,transform 動(dòng)畫(huà)由GPU控制,支持硬件加速。
看完以上兩個(gè)例子,那么我們就要入正題了。
主線程和合成線程
現(xiàn)代瀏覽器通常由兩個(gè)重要的線程組成(主線程 和 合成線程)。這兩個(gè)線程一起工作完成繪制頁(yè)面的任務(wù):
主線程需要做的任務(wù)如下:
- 運(yùn)行Javascript
- 計(jì)算HTML元素的CSS樣式
- layout (relayout)
- 將頁(yè)面元素繪制成一張或多張位圖
- 將位圖發(fā)送給合成線程
合成線程主要任務(wù)是:
- 利用GPU將位圖繪制到屏幕上
- 讓主線程將可見(jiàn)的或即將可見(jiàn)的位圖發(fā)給自己
- 計(jì)算哪部分頁(yè)面是可見(jiàn)的
- 計(jì)算哪部分頁(yè)面是即將可見(jiàn)的(當(dāng)你的滾動(dòng)頁(yè)面的時(shí)候)
- 在你滾動(dòng)時(shí)移動(dòng)部分頁(yè)面
在很長(zhǎng)的一段時(shí)間內(nèi),主線程都在忙于運(yùn)行Javascript和繪制元素。
例如,當(dāng)用戶滾動(dòng)一個(gè)頁(yè)面時(shí),合成線程會(huì)讓主線程提供最新的可見(jiàn)部分的頁(yè)面位圖。然而主線程不能及時(shí)的響應(yīng)。這時(shí)合成線程不會(huì)等待,它會(huì)繪制已有的頁(yè)面位圖。對(duì)于沒(méi)有的部分則繪制白屏。
GPU擅長(zhǎng)的領(lǐng)域:
我們來(lái)看一個(gè)例子:將一個(gè)頁(yè)面元素的高度從100px漸變到200px,方法可以是:1、height 2、transform: scale(1.0)。兩個(gè)方法性能是不一樣的,現(xiàn)在我們來(lái)從主線程和合成線程的角度來(lái)看看
傳統(tǒng)的方法:改變 height
div {height: 100px;transition: height 1s linear; }div:hover {height: 200px; }下圖是一張主線程和合成線程的互相交互的時(shí)間線圖。
黃色盒子的操作是潛在耗時(shí)較長(zhǎng)的,藍(lán)色盒子的操作是很快的。在transition動(dòng)畫(huà)的每一幀中,都修改元素的高度,這可能會(huì)導(dǎo)致子元素的大小也會(huì)變化,然后瀏覽器不得不進(jìn)行relayout。在relayout之后主線程還需要重新生成元素的位圖,加載位圖到GPU內(nèi)存中
css3的方法:transform
直接改變?cè)氐母叨仁呛芎臅r(shí)的,但我們可以使用 transform: scale(); 來(lái)縮放元素,實(shí)現(xiàn)這個(gè)改變高度的目的。
div {transform: scale(0.5);transition: transform 1s linear; }div:hover {transform: scale(1.0); }黃色盒子的操作是潛在耗時(shí)較長(zhǎng)的,藍(lán)色盒子的操作是很快的。CSS transform屬性并不會(huì)觸發(fā)當(dāng)前元素或附近元素的relayout。瀏覽器將當(dāng)前元素視為一個(gè)整體,它會(huì)縮放、旋轉(zhuǎn)、移動(dòng)這一整個(gè)元素。
瀏覽器只需要在動(dòng)畫(huà)開(kāi)始之時(shí)生成位圖,然后將位圖發(fā)送給GPU。之后瀏覽器不需要做額外的relayout和repaint,甚至不需要發(fā)送位圖給GPU。瀏覽器只需要充分發(fā)揮GPU的長(zhǎng)處:繪制同一張位圖到不同的位置、旋轉(zhuǎn)角度和縮放比例。
可以使用GPU加速的CSS3屬性
- CSS transform
- CSS opacity
- CSS filter
感想
既然transform這個(gè)屬性那么強(qiáng)大,我們就可以用他來(lái)優(yōu)化我們平時(shí)的一下操作。例如:拖拽,在mouseover階段就用transform,在mousedown階段在再用position絕對(duì)定位,這樣是不是就可以減少repaint和reflow的操作呢。還有就是動(dòng)畫(huà)。等等。
參考資料
CSS動(dòng)畫(huà)之硬件加速
CSS animation和transition的性能探究
總結(jié)
以上是生活随笔為你收集整理的position: absolute;_前端性能优化--transform与position的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java单纯形法_单纯形法 - fjzz
- 下一篇: java 且_JAVA中逻辑运算符“|”