前言
上週我與阿里的宇果有一次技術的交流,然後對天貓H5站點做了一些淺層次的分析,後面點時間基本天天都會有聯絡,中途聊了一些技術細節、聊了雙方團隊在幹什麼,最後聊到了前端優化。因為我本身參與了幾次攜程H5站點的優化,在這方面有一些心得,但是與宇果交流的過程中發現我們在優化的時候忽略了一些細節。
攜程做優化的時候整個重心基本放到了尺寸的縮減,和宇果的交流過程中他提出了渲染優化,其實渲染優化無非是減少迴流,對於減少迴流我們也有一些概念,我一直認為這個事情應該業務開發關注而不是框架關注(事實上框架也無法關注),所以對一些BUG採取了表現層面的解決,卻對真相視而不見的做法,現在想來真的有點無知,這裡便以一個原來的渲染BUG為切入點,將最近與宇果的交流所得整理下。
宇果部落格:http://www.ghugo.com/
迴流與重繪
首先,我們再次複習一下回流與重繪的知識,瀏覽器會解析三個東西:HTML、Javascript、CSS。
瀏覽器首先會根據HTML生成DOM Tree,其次會根據CSS生成CSS Rule Tree,javascript可以通過DOM API與CSS API操作DOM Tree與CSS Rule Tree,從而引起頁面變化。
瀏覽器解析結束會通過DOM Tree與CSS Rule Tree形成render tree,只有display不為none的元素才會形成render Tree,render Tree形成後瀏覽器會呼叫GUI繪製頁面,在此之前做的一件事情便是layout或者說reflow。上面的描述簡單而言可以分為以下流程:
l 生成DOM樹
l 計算CSS樣式
l 構建render tree
l reflow,定位元素位置大小
l 繪製頁面
在這個過程中,若是javascript動態改變DOM Tree便會引起reflow
頁面中的元素改變,只要不影響尺寸,比如只是顏色改變只會引起repaint不會引起迴流
否則,reflow不可避免,這個時候便需要重新計算形成render Tree
reflow分為區域性迴流與全域性迴流,會影響下面的,不會影響上面的元素
reflow耗用的系統資源較大,DOM Tree中受到影響的節點皆會reflow,然後影響其子節點最壞的情況是所有節點reflow,該問題引發的現象便是低效能的電腦風扇不停的轉,手機變得很熱,並且非常耗電,以下操作可能引起reflow
l 操作dom結構
l 動畫
l DOM樣式修改
l 獲取元素尺寸的API
android大屏手機渲染BUG
這個是我們一個tab元件,這個元件按道理說非常簡單:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta name="viewport" content="width=320.1,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"> 5 <title></title> 6 <style type="text/css"> 7 body { -webkit-text-size-adjust: none; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-font-smoothing: antialiased; -moz-user-select: none; } 8 9 ul, ol { list-style: none; margin: 0; padding: 0; } 10 11 .cui-tab-mod { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; height: 43px; line-height: 43px; border-bottom: #bcbcbc 1px solid; background-color: #fafafa; color: #666; font-size: 15px; position: relative; display: table\9; width: 100%; } 12 13 .cui-tab-mod li { text-align: center; -webkit-box-flex: 1; -moz-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; display: table-cell\9; } 14 15 .cui-tab-mod li.cui-tab-current { color: #099fde; } 16 17 .cui-tab-mod .cui-tab-scrollbar { position: absolute; left: 0; height: 4px; bottom: -1px; background-color: #099fde; -webkit-transition: -webkit-transform 300ms ease-in-out; -moz-transition: -moz-transform 300ms ease-in-out; -ms-transition: -ms-transform 300ms ease-in-out; transition: transform 300ms ease-in-out; z-index: -1; } 18 19 .cui-tabnum2 { width: 50%; } 20 21 .cui-tabnum3 { width: 33.33333%; } 22 23 .cui-tabnum4 { width: 25%; } 24 25 .cui-tabnum5 { width: 20%; } 26 27 .cui-tabnum6 { width: 16.66666%; } 28 29 .cui-tab-mod li.cui-tab-current ~ .cui-tab-scrollbar { z-index: 2; } 30 31 .cui-tab-mod li:nth-of-type(1).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(0,0,0); -moz-transform: translate3d(0,0,0); -ms-transform: translate3d(0,0,0); transform: translate3d(0,0,0); } 32 33 .cui-tab-mod li:nth-of-type(2).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(100%,0,0); -moz-transform: translate3d(100%,0,0); -ms-transform: translate3d(100%,0,0); transform: translate3d(100%,0,0); } 34 35 .cui-tab-mod li:nth-of-type(3).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(200%,0,0); -moz-transform: translate3d(200%,0,0); -ms-transform: translate3d(200%,0,0); transform: translate3d(200%,0,0); } 36 37 .cui-tab-mod li:nth-of-type(4).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(300%,0,0); -moz-transform: translate3d(300%,0,0); -ms-transform: translate3d(300%,0,0); transform: translate3d(300%,0,0); } 38 39 .cui-tab-mod li:nth-of-type(5).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(400%,0,0); -moz-transform: translate3d(400%,0,0); -ms-transform: translate3d(400%,0,0); transform: translate3d(400%,0,0); } 40 41 .cui-tab-mod li:nth-of-type(6).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(500%,0,0); -moz-transform: translate3d(500%,0,0); -ms-transform: translate3d(500%,0,0); transform: translate3d(500%,0,0); } 42 </style> 43 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> 44 </head> 45 <body> 46 47 <ul class="cui-tab-mod"> 48 <li data-key="0" data-index="0" class="cui-item cui-tab-current">中國</li> 49 <li data-key="1" data-index="1" class="cui-item">美國</li> 50 <li data-key="2" data-index="2" class="cui-item">日本</li> 51 <i class="cui-tab-scrollbar cui-tabnum3"></i> 52 </ul> 53 <script type="text/javascript"> 54 $(function () { 55 var wrapper = $('.cui-tab-mod'); 56 wrapper.on('click', function (e) { 57 var el = $(e.target); 58 if (el.hasClass('cui-item')) { 59 wrapper.find('li').removeClass('cui-tab-current'); 60 el.addClass('cui-tab-current'); 61 } 62 }); 63 }); 64 </script> 65 </body> 66 </html>
點選一下就讓當前item獲取class,然後文字樣式會改變,下面一個橫線也會動畫滑動過去,但是這個東西在android大屏手機上卻出了問題(比如note2),他會這樣表現:
如圖所示,class過去了,文字顏色也變了,但是下面對應的豎條卻沒有過去,我當時一看就知道是渲染的問題並且馬上給出了一個解決方案:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta name="viewport" content="width=320.1,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"> 5 <title></title> 6 <style type="text/css"> 7 body { -webkit-text-size-adjust: none; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-font-smoothing: antialiased; -moz-user-select: none; } 8 9 ul, ol { list-style: none; margin: 0; padding: 0; } 10 11 .cui-tab-mod { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; height: 43px; line-height: 43px; border-bottom: #bcbcbc 1px solid; background-color: #fafafa; color: #666; font-size: 15px; position: relative; display: table\9; width: 100%; } 12 13 .cui-tab-mod li { text-align: center; -webkit-box-flex: 1; -moz-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; display: table-cell\9; } 14 15 .cui-tab-mod li.cui-tab-current { color: #099fde; } 16 17 .cui-tab-mod .cui-tab-scrollbar { position: absolute; left: 0; height: 4px; bottom: -1px; background-color: #099fde; -webkit-transition: -webkit-transform 300ms ease-in-out; -moz-transition: -moz-transform 300ms ease-in-out; -ms-transition: -ms-transform 300ms ease-in-out; transition: transform 300ms ease-in-out; z-index: -1; } 18 19 .cui-tabnum2 { width: 50%; } 20 21 .cui-tabnum3 { width: 33.33333%; } 22 23 .cui-tabnum4 { width: 25%; } 24 25 .cui-tabnum5 { width: 20%; } 26 27 .cui-tabnum6 { width: 16.66666%; } 28 29 .cui-tab-mod li.cui-tab-current ~ .cui-tab-scrollbar { z-index: 2; } 30 31 .cui-tab-mod li:nth-of-type(1).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(0,0,0); -moz-transform: translate3d(0,0,0); -ms-transform: translate3d(0,0,0); transform: translate3d(0,0,0); } 32 33 .cui-tab-mod li:nth-of-type(2).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(100%,0,0); -moz-transform: translate3d(100%,0,0); -ms-transform: translate3d(100%,0,0); transform: translate3d(100%,0,0); } 34 35 .cui-tab-mod li:nth-of-type(3).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(200%,0,0); -moz-transform: translate3d(200%,0,0); -ms-transform: translate3d(200%,0,0); transform: translate3d(200%,0,0); } 36 37 .cui-tab-mod li:nth-of-type(4).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(300%,0,0); -moz-transform: translate3d(300%,0,0); -ms-transform: translate3d(300%,0,0); transform: translate3d(300%,0,0); } 38 39 .cui-tab-mod li:nth-of-type(5).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(400%,0,0); -moz-transform: translate3d(400%,0,0); -ms-transform: translate3d(400%,0,0); transform: translate3d(400%,0,0); } 40 41 .cui-tab-mod li:nth-of-type(6).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(500%,0,0); -moz-transform: translate3d(500%,0,0); -ms-transform: translate3d(500%,0,0); transform: translate3d(500%,0,0); } 42 </style> 43 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> 44 </head> 45 <body> 46 47 <ul class="cui-tab-mod"> 48 <li data-key="0" data-index="0" class="cui-item cui-tab-current">中國</li> 49 <li data-key="1" data-index="1" class="cui-item">美國</li> 50 <li data-key="2" data-index="2" class="cui-item">日本</li> 51 <i class="cui-tab-scrollbar cui-tabnum3"></i> 52 </ul> 53 <script type="text/javascript"> 54 $(function () { 55 var wrapper = $('.cui-tab-mod'); 56 wrapper.on('click', function (e) { 57 var el = $(e.target); 58 var toolBar = $('.cui-tab-scrollbar'); 59 if (el.hasClass('cui-item')) { 60 wrapper.find('li').removeClass('cui-tab-current'); 61 el.addClass('cui-tab-current'); 62 setTimeout(function () { 63 toolBar.width('width', toolBar.width()); 64 }, 0) 65 } 66 }); 67 }); 68 </script> 69 </body> 70 </html>
這裡設定下劃線width的時候觸發了其迴流,而setTimeout會在主程式執行結束後才觸發,於是BUG修復了,核心程式碼如下:
1 $(function () { 2 var wrapper = $('.cui-tab-mod'); 3 wrapper.on('click', function (e) { 4 var el = $(e.target); 5 var toolBar = $('.cui-tab-scrollbar'); 6 if (el.hasClass('cui-item')) { 7 wrapper.find('li').removeClass('cui-tab-current'); 8 el.addClass('cui-tab-current'); 9 //修復丟幀問題 10 setTimeout(function () { 11 toolBar.width('width', toolBar.width()); 12 }, 0) 13 } 14 }); 15 });
這個BUG解決後也沒有再關注,時序紛飛,一年過去了卻和宇果聊天過程中再次想起這個問題,才意識到自己忽略的是什麼。
重新認識Timeline
我們常常有一個問題,如何知道頁面哪裡的渲染有問題,如何捕捉?
如果沒有一個實際可用的工具的話,我們只能由外文或者部落格獲取這類知識,這個時候就和我解決上述問題差不多了,僅僅從皮毛上知道是渲染導致的問題,並且能使用迴流解決問題,卻是對渲染效能造成負擔,所以如何捕捉渲染問題衡量渲染效能這個是第一位,好在chrome提供了Timeline:
以我們的頁面為例,我們開始監控,這裡稍微改變一下程式碼:
1 var wrapper = $('.cui-tab-mod'); 2 wrapper.on('click', function (e) { 3 var el = $(e.target); 4 var toolBar = $('.cui-tab-scrollbar'); 5 if (el.hasClass('cui-item')) { 6 wrapper.find('li').removeClass('cui-tab-current'); 7 el.addClass('cui-tab-current'); 8 // setTimeout(function () { 9 // toolBar.width('width', toolBar.width()); 10 // }, 0) 11 } 12 }); 13 14 function setIndex(i) { 15 var els = wrapper.find('li'); 16 els.removeClass('cui-tab-current'); 17 els.eq(i).addClass('cui-tab-current'); 18 }
我首先點選開始監控,然後滑鼠不在頁面做任何操作,在控制檯輸入一句:
setIndex(1)
於是頁面會發生改變,這個時候,我們得到的圖是:
這張圖其實最初我也是看熱鬧的,昨天根據宇果的指點,才稍微看出點門道了:
首先請看上圖中的一個個透明框,每個透明框便是兩次顯示器重新整理週期中等待的時間,其中有一個非常關鍵的單位叫做fps,這個60fps是個什麼東西呢?
60fps與16ms
所謂60fps便是說螢幕1s會重新整理60次,意思是大概16.5ms螢幕會重新整理一次,在這一次重新整理中瀏覽器會幹很多事情,這裡還是以圖示為例,這裡有2個前提:
① 我們滑鼠並未操作
② 我們頁面很單一
所以在我們執行setIndex前,瀏覽器根本沒有任何消耗,每一次的重新整理干了這幾件事情:
剛剛整個過程一過經過了2.29秒,瀏覽器發生了這些事情:
從白條來看,瀏覽器處理整個動作大概花費320ms,這裡出了4種顏色,這個也比較關鍵。
4種顏色
黃色是說明正在執行javascript指令碼,從這裡可以看出,js執行的速度是非常快的,這裡包含了設值class、移除class,獲取width等一系列操作,瀏覽器會等一次結束後才發生渲染。
紫色是說明正在迴流,也就是我們傳說中的渲染,這個是非常耗費效能的,我們這裡具體跟進去看看:
接下來觸發了css3過渡transition的動畫,下面的滾動條開始了不停的移動:
可以看到,後續所有的運動隻影響了一個元素,這個元素便是滾動條,這裡為了驗證剛剛所說,我們做兩個事情:
① 使用click觸發索引更改
② 為下劃線新增子元素
這裡有個非常不同的就是,我滑鼠在介面操作了,不可避免的會引起一些move樣式改變,所以有重繪有迴流,都比較輕,比較關鍵的是,其中多了一個click操作(Event),但是下面動畫時候影響的元素仍然只是一個,這個有點不明原因,我這裡特別將transform改成了left,因為transform更加平滑,我想找出原因,卻發現了另一個現象:
可以看出transformd導致的動畫只會執行一次paint,便是最初那一次,而使用left的話卻在不停的paint,這個是資源消耗的對比:
可以看出,使用left時候出現了鋸齒狀,這個時候我們可以得出一個結論,transform的動畫確實比left節省效能。
至此我們對chrome的Timeline有了一個新的認識,但是我們這裡的觀察全部是在PC端發生的,而手機端是怎麼樣的呢?
移動端的渲染
這個圖與上圖形成了鮮明對比,PC端就只有很小的波動,手機端卻引起了很多漣漪,導致這個問題的原因是硬體設施(這裡是盜圖):
PS:這裡苦於沒有Android裝置,chrome電腦又暫時抽風不能真機除錯,便去同事那裡草草截圖,哎......
丟幀的發生
如前所述,瀏覽器一次的重新整理約16ms,以一次原子行為來說是這樣的:
指令碼執行時間+渲染時間+繪製時間<16ms
如果中間有一次的操作比如渲染的時間大於了16ms而導致瀏覽器沒有來得及繪製,那麼那次的操作便失效了,這個就是所謂的丟幀。
我們在note2上執行程式時會導致丟幀,應該就是其中一次超出了時限,因為class變化會引起樣式重新計算,但是隻是文字變化的話只是會引起重繪,所以主要問題發生在transition動畫。
而我們的解決方案是setTimeout,這個造成的影響是:
我們發現了,就算沒有動畫,重新計算樣式那裡依舊是主要導致的迴流的因素,是他擠掉了後續的操作嗎?他重新計算樣式中的因素有很多,我懷疑的目光首先放到了這段css:
.cui-tab-mod li:nth-of-type(1).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0); -ms-transform: translate3d(0,0,0); transform: translate3d(0,0,0); }
測試下來,似乎與他相關:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta name="viewport" content="width=320.1,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"> 5 <title></title> 6 <style type="text/css"> 7 body { -webkit-text-size-adjust: none; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-font-smoothing: antialiased; -moz-user-select: none; } 8 ul, ol { list-style: none; margin: 0; padding: 0; } 9 .cui-tab-mod { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; height: 43px; line-height: 43px; border-bottom: #bcbcbc 1px solid; background-color: #fafafa; color: #666; font-size: 15px; position: relative; display: table\9; width: 100%; } 10 .cui-tab-mod li { text-align: center; -webkit-box-flex: 1; -moz-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; display: table-cell\9; } 11 .cui-tab-mod li.cui-tab-current { color: #099fde; } 12 .cui-tab-mod .cui-tab-scrollbar { position: absolute; left: 0; height: 4px; bottom: -1px; background-color: #099fde; -webkit-transition: -webkit-transform 300ms ease ; transition: transform 300ms ease ; z-index: -1; -webkit-backface-visibility:hidden; backface-visibility:hidden; } 13 .cui-tabnum2 { width: 50%; } 14 .cui-tabnum3 { width: 33.33333%; } 15 .cui-tab-mod li.cui-tab-current ~ .cui-tab-scrollbar { z-index: 2; } 16 </style> 17 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> 18 </head> 19 <body> 20 <ul class="cui-tab-mod"> 21 <li data-key="0" data-index="0" class="cui-item cui-tab-current">中國</li> 22 <li data-key="1" data-index="1" class="cui-item">美國</li> 23 <li data-key="2" data-index="2" class="cui-item">日本</li> 24 <i class="cui-tab-scrollbar cui-tabnum3"><span>1</span></i> 25 </ul> 26 <script type="text/javascript"> 27 var wrapper = $('.cui-tab-mod'); 28 var toolBar = $('.cui-tab-scrollbar'); 29 var els = wrapper.find('li'); 30 wrapper.on('click', function (e) { 31 toolBar.css({ 32 '-webkit-transform': 'translate3d(100%,0,0)', 33 'transform': 'translate3d(100%,0,0)' 34 }) 35 var el = $(e.target); 36 }); 37 </script> 38 </body> 39 </html>
如果這樣,我直接操作toolBar便可以繞過該BUG,但是我還是不太確定,所以有了這段程式碼:
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta name="viewport" content="width=320.1,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"> 5 <title></title> 6 <style type="text/css"> 7 body { -webkit-text-size-adjust: none; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-font-smoothing: antialiased; -moz-user-select: none; } 8 9 ul, ol { list-style: none; margin: 0; padding: 0; } 10 11 .cui-tab-mod { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; height: 43px; line-height: 43px; border-bottom: #bcbcbc 1px solid; background-color: #fafafa; color: #666; font-size: 15px; position: relative; display: table\9; width: 100%; } 12 13 .cui-tab-mod li { text-align: center; -webkit-box-flex: 1; -moz-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; display: table-cell\9; } 14 15 .cui-tab-mod li.cui-tab-current { color: #099fde; } 16 17 .cui-tab-mod .cui-tab-scrollbar { position: absolute; left: 0; height: 4px; bottom: -1px; background-color: #099fde; -webkit-transition: -webkit-transform 300ms ease ; transition: transform 300ms ease ; z-index: -1; -webkit-backface-visibility:hidden; backface-visibility:hidden; } 18 19 .cui-tabnum2 { width: 50%; } 20 21 .cui-tabnum3 { width: 33.33333%; } 22 23 .cui-tabnum4 { width: 25%; } 24 25 .cui-tabnum5 { width: 20%; } 26 27 .cui-tabnum6 { width: 16.66666%; } 28 29 .cui-tab-mod li.cui-tab-current ~ .cui-tab-scrollbar { z-index: 2; } 30 31 .cui-tab-mod cui-tab-current .cui-tab-scrollbar { -webkit-transform: translate3d(100%,0,0); -moz-transform: translate3d(100%,0,0); -ms-transform: translate3d(100%,0,0); transform: translate3d(100%,0,0); } 32 33 34 .cui-tab-mod li:nth-of-type(1).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(0,0,0); -moz-transform: translate3d(0,0,0); -ms-transform: translate3d(0,0,0); transform: translate3d(0,0,0); } 35 36 .cui-tab-mod li:nth-of-type(2).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(100%,0,0); -moz-transform: translate3d(100%,0,0); -ms-transform: translate3d(100%,0,0); transform: translate3d(100%,0,0); } 37 38 .cui-tab-mod li:nth-of-type(3).cui-tab-current ~ .cui-tab-scrollbar { -webkit-transform: translate3d(200%,0,0); -moz-transform: translate3d(200%,0,0); -ms-transform: translate3d(200%,0,0); transform: translate3d(200%,0,0); } 39 40 </style> 41 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> 42 </head> 43 <body> 44 45 <ul class="cui-tab-mod"> 46 <li data-key="0" data-index="0" class="cui-item cui-tab-current">中國</li> 47 <li data-key="1" data-index="1" class="cui-item">美國</li> 48 <li data-key="2" data-index="2" class="cui-item">日本</li> 49 <i class="cui-tab-scrollbar cui-tabnum3"><span>1</span></i> 50 </ul> 51 <script type="text/javascript"> 52 var wrapper = $('.cui-tab-mod'); 53 var toolBar = $('.cui-tab-scrollbar'); 54 var els = wrapper.find('li'); 55 56 wrapper.on('click', function (e) { 57 var el = $(e.target); 58 els.removeClass('cui-tab-current'); 59 el.addClass('cui-tab-current'); 60 toolBar.css('left', '0'); 61 62 // setTimeout(function () { 63 // toolBar.width('width', toolBar.width()); 64 // }, 0) 65 }); 66 67 68 69 </script> 70 </body> 71 </html>
1 var wrapper = $('.cui-tab-mod'); 2 var toolBar = $('.cui-tab-scrollbar'); 3 var els = wrapper.find('li'); 4 5 wrapper.on('click', function (e) { 6 var el = $(e.target); 7 els.removeClass('cui-tab-current'); 8 el.addClass('cui-tab-current'); 9 toolBar.css('left', '0'); 10 11 // setTimeout(function () { 12 // toolBar.width('width', toolBar.width()); 13 // }, 0) 14 });
這一段程式碼也可以解決BUG,似乎解決bug的元素是導致了absolute元素的迴流而與其它無關,這裡再次對比Timeline:
兩次對比沒有什麼差距,這個BUG導致的原因還需要深究,待我哪天去真機測試......
setTimeout動畫
另外,最好也不要使用setTimeout之類的定時器來實現動畫,下面這個動畫操作也是非常消耗的:
這裡如果使用requestAnimationFrame便可以避免Timer的影響。
fixed元素
一般來說,fixed元素在手機上尤其卡,我們這裡也來追蹤一下原因:
可以看到,fixed元素與left一樣的都會不斷的Paint,所以他卡呢,至於如何避免不同的團隊有不同的方案。
結語
今天回顧了與宇果的交流過程中的渲染優化相關,這裡還停留在比較淺的層次,需要繼續學習,希望對各位有用,文中有誤請您提出,最後微博求粉: