摘要
此bug出現(xiàn)需要條件:父元素需使用絕對定位absolute或固定定位fixed尚洽,使用overflow: scroll / auto(或overflow-y: scroll / auto)磨隘,內(nèi)部子元素是動態(tài)大兴狻(例如較大的svg document到忽,近似為內(nèi)嵌iframe橄教,等等)清寇。
描述:
最近在項目中遇見的,比較奇異护蝶。最外層的div設(shè)置定位华烟,里面的兩個模塊(main1、main2)設(shè)置了相對定位持灰。并且這兩個模塊通過v-if判斷盔夜,只能出現(xiàn)一個。main1里面有很多的其他元素組成堤魁,里面還分有多個小模塊喂链,且小模塊都設(shè)置有高度。main2是動態(tài)生成的圖片撐起來的高度妥泉,設(shè)置高度為100vh椭微,在main2內(nèi)只有定位設(shè)置一個信息提示。
結(jié)果:main1能正趁ち矗滑動蝇率,main2在iOS部分(當時是ios10.x,ios11.x)系統(tǒng)機器不能滑動刽沾。
bug出現(xiàn)原因:沒有相關(guān)官方文檔描述該bug本慕。在查閱文檔及自己測試的時候總結(jié):iOS safari 會將overflow:scroll的元素識別為一個單獨的 ScrollView,并予以一個 -webkit-overflow-scrolling 屬性為auto侧漓。而safari中的網(wǎng)頁本身就是一個大的ScrollView锅尘,在脫離文檔流的定位時,子元素的高度如果沒有在ScrollView建立之前確定布蔗,就不會觸發(fā)內(nèi)部滑動藤违,而會觸發(fā)外部滑動。
關(guān)于 -webkit-overflow-scrolling:Safari CSS Reference官方是這樣描述的:
Specifies whether to use native-style scrolling in an overflow:scroll element.
分析
1.父元素不脫離文檔流時何鸡,無此bug纺弊。
2.父元素在不指定 -webkit-overflow-scrolling:touch時必定出現(xiàn)無法滑動的問題。
3.當內(nèi)部元素為正常的html元素時骡男,無此bug。
4.當為父元素重新設(shè)置overflow屬性時傍睹,可能會導(dǎo)致safari重建ScrollView而bug消失隔盛。(之前版本的實驗室用這種方法解決的,但新海外版不能用這種方法fix拾稳,所以是可能)
解決方法
1.必須為所有在移動端的overflow: scroll元素增加屬性 -webkit-overflow-scrolling: touch吮炕。
2.當父元素可不脫離文檔流時不要脫離文檔流。
3.在子元素iframe加載完成后可異步將父元素的overflow: scroll屬性重寫(此方法可能不成功)访得。
4.如以上沒有解決龙亲,則給予子元素一個min-height陕凹,大小不限(略大于效果最好),幫助safari建立ScrollView(親測最有效)鳄炉。
后續(xù)
之后瀏覽文章的時候發(fā)現(xiàn)了原因杜耙,記錄下:
究其原因,是因為我在頁面上放了很多張圖片讓其自行占位拂盯,而在頁面剛加載時佑女,其他瀏覽器會預(yù)先獲取到圖片的大小而給其一個占位,無論圖片是否加載完成頁面總高度固定的谈竿。而safari就不一樣团驱,圖片沒加載成功時高度是0。
圖片沒加載成功時高度是0!!!!
哦豁空凸,這個要牢記嚎花,以后能多避坑
safari瀏覽器在渲染頁面元素的時候,會預(yù)先走webkit瀏覽器的渲染流程:
1.構(gòu)建DOM tree
2.構(gòu)建CSS rule tree
3.根據(jù)DOM和CSS tree來構(gòu)建render tree
4.根據(jù)render tree計算頁面的layout
5.render頁面
注意在第三步和第四步的時候呀洲,safari瀏覽器在構(gòu)建render tree的時候贩幻,會預(yù)先找到相應(yīng)的overflow: scroll元素,在計算頁面layout的時候两嘴,會計算父元素的高度與子元素的高度丛楚,若子元素高于父元素,則在render頁面時為其建立一個原生的scrollView憔辫。
這個scrollView有什么用的趣些?其實就是為了給其一個彈彈樂的效果(但確實用戶體驗不錯)。
當子元素是某個媒體格式時贰您,比如img坏平、object(svg)等,safari在加載完成之前是不會在計算在layout之內(nèi)的锦亦,也就是高度為0舶替,則子元素的高度就一定小于父元素的高度,safari不會給父元素一個原生的scrollView杠园。