原:http://www.iunbug.com/archives/2012/09/19/411.html
已經有不少前端同行抱怨iScroll4的各種問題,我個人並不贊同將這些問題歸咎於iScroll4,因為iScroll4進無論是touch事件的捕獲,還是使用transform來處理滾動,以及將cubic-bezier應
用到transition上實現高效的平滑滾動,這些原理我們都是已知的。更多原理細節可以參看[譯]手把手教你編寫iOS上Mobile Web App實現Fixed Position和模擬滾動 一文。此文則來解釋另一個
被很多人誤解為iScroll4 造成的問題,那就是內容多的頁面閃動的問題。現象表現為:
1.滑動過程中,滾動區內的元素在釋放手指時出現細微閃動
2.圖片縮放過程中釋放手指時明顯閃動
3.iOS上從mobile safari打開或第三方應用內打開后,切回主屏幕再切回頁面時明顯閃動
4.頁面初始時閃動
大致這些情況下會有閃動,在ipad2,new ipad上會明顯看得出。
下面就來分析產生的原因和解決辦法:
首先,我們知道iOS5給我們帶來了
overflow-y: scroll; overflow-x: hidden; -webkit-overflow-scrolling: touch;
實現固定區域內的滾動,當應用這種方式實現滾動時,上面的提到的現象也會不同程度的出現尤其是1,2.是那么我們就可以斷定不是iScroll4 的原因了。那么究竟是什么原因呢?
webkit在繪制頁面時會將結構分為各種層,當層足夠大時就會變成很大的平鋪層。這各一來webkit在每次頁面結構發生變化時不需要都渲染整個頁面而是渲染對應層了,這對渲染速度來說相當的重要。webkit會給各種層分配一定大小的“備份存儲區”在內存里緩存起來,這就是繪制層的上下文,通過這個上下文就可以很容易的實現各種效果(動畫,3D變換等),“備份存儲區”內存占用大小不僅依層而定,跟設備和顯示方式也是有關的,假設這在普通屏幕下是1:1的,但在Retina屏幕下則是1:2的,並且放大時這個量會成倍增加;一張圖片是10X10,普通屏幕分配的就是10X10,Retina初始則是20X20。這也表明Retina是更加消耗內存的。當層很大時,意味着“備份存儲區”會消耗更大的內存,為了避免這點,webkit並不會繪制一個很大的層來存儲一個很大的頁面,比如說平鋪層則會拆分成很多的塊來繪制,即盡占用盡可能小的內存,只是將可視范圍內的那部分渲染出來。這就是為什么我們在大頁面滾動時會發現下面的內容慢慢顯示,向上滾動時上面的內容還慢慢顯示的原因。
以下則是webkit划分為層繪制的場景:
- 頁面主容器永遠是獨立的平鋪層
- 繪制密集型元素時,如<video>, <canvas>
- 應用3D transformations的元素,包括translate3d, rotate3d, translateZ
- 內容被加強時,如Filters, masks, reflections, opacity, transitions, animations
- 某些特殊的情況下也會,如position:fixed, -webkit-overflow-scroll:touch
- 任何在已知層上覆蓋的內容
這對我們解決閃動問題有什么幫助呢?按上頁的說明,和iScroll4實現原理我們很容易知道,iScroll4作用的滾動區是一個很大的獨立層,webkit是不會將這么大的層整個分配內存繪制渲染的,所以,只要將滾動區域可視范圍的列表項元素緩存起來就解決這個問題了。記webkit強制緩存起來即是將他們獨立成一個層,而且這個層當然不會很大否則會被視為平鋪層處理了。一般列表里項里的元素不會像頁面主容器一樣的大的。實現方式就是將列表項置身於上面的6個場景中,比如:
#wrap>section>article{-webkit-transform:translateZ(0);}/*注意這里*/ <div id="wrap"> <section> <article>1</article> <article>2</article> <article>3</article> </section> </div>