1. 程式人生 > >iOS safari瀏覽器上overflow: scroll元素無法滾動bug深究

iOS safari瀏覽器上overflow: scroll元素無法滾動bug深究

前情提要

在之前我寫過一篇文章:iOS safari瀏覽器上overflow: scroll元素無法滑動bug解決方法整理,這篇文章寫的是,當iOS safari瀏覽器上出現大於父容器的svg元素,想給父容器加上overflow: scroll實現內部滾動效果而失敗的總結。但當時並沒有意識到這個問題的實際原理,只是知道了safari給scroll元素加入了原生的scrollView塊

bug原理

最近在做一個專案的時候,在safari上遇到了一個其他的bug,卻讓我意識到了這個問題的終極原因。

專案bug是這樣的:我在用Nuxt做一個展示站點,需要使用錨鏈接在頁面剛進入的時候跳轉到某個位置。這裡我本來使用的是router api提供的scrollBehavior

方法,但這個方法在Nuxt上有侷限性。我就把實現方式改為:進入頁面後,動態計算不同錨點位置的scroll top再設定父元素的scroll位置。

在其他瀏覽器上都是ok的,但在safari上就出了問題:在頁面剛進入時無法正確獲取到元素的scroll top,小很多,只有頁面載入完成之後才可以。

究其原因,是因為我在頁面上放了很多張圖片讓其自行佔位,而在頁面剛載入時,其他瀏覽器會預先獲取到圖片的大小而給其一個佔位,無論圖片是否載入完成頁面總高度固定的。而safari就不一樣,圖片沒載入成功時高度是0

圖片沒載入成功時高度是0。哇長見識了。

這時回想到之前在safari上的那個scroll bug,在查閱相關資料後就可以得出結論了:

safari瀏覽器在渲染頁面元素的時候,會預先走webkit瀏覽器的渲染流程:

  1. 構建DOM tree
  2. 構建CSS rule tree
  3. 根據DOM和CSS tree來構建render tree
  4. 根據render tree計算頁面的layout
  5. render頁面

注意在第三步和第四步的時候,safari瀏覽器在構建render tree的時候,會預先找到相應的overflow: scroll元素,在計算頁面layout的時候,會計算父元素的高度與子元素的高度,若子元素高於父元素,則在render頁面時為其建立一個原生的scrollView。

這個scrollView有什麼用的?其實就是為了給其一個彈彈樂的效果(但確實使用者體驗不錯)。

當子元素是某個媒體格式時,比如img、object(svg)等,safari在載入完成之前是不會在計算在layout之內的,也就是高度為0,則子元素的高度就一定小於父元素的高度,safari不會給父元素一個原生的scrollView。

解決方法

反其道而行之。當出現這種問題的時候,給子元素一個包裹元素,包裹元素設定一個min-height大於父元素的高度,讓父元素有scrollView。當子元素載入完成時,將包裹元素撐開,父元素便可以自由滾動了。