iOS safari浏览器上overflow: scroll元素没法滚动bug深究

前情提要

在以前我写过一篇文章:iOS safari浏览器上overflow: scroll元素没法滑动bug解决方法整理,这篇文章写的是,当iOS safari浏览器上出现大于父容器的svg元素,想给父容器加上overflow: scroll实现内部滚动效果而失败的总结。但当时并无意识到这个问题的实际原理,只是知道了safari给scroll元素加入了原生的scrollView块web

bug原理

最近在作一个项目的时候,在safari上遇到了一个其余的bug,却让我意识到了这个问题的终极缘由。segmentfault

项目bug是这样的:我在用Nuxt作一个展现站点,须要使用锚连接在页面刚进入的时候跳转到某个位置。这里我原本使用的是router api提供的scrollBehavior方法,但这个方法在Nuxt上有局限性。我就把实现方式改成:进入页面后,动态计算不一样锚点位置的scroll top再设置父元素的scroll位置。api

在其余浏览器上都是ok的,但在safari上就出了问题:在页面刚进入时没法正确获取到元素的scroll top,小不少,只有页面加载完成以后才能够。浏览器

究其缘由,是由于我在页面上放了不少张图片让其自行占位,而在页面刚加载时,其余浏览器会预先获取到图片的大小而给其一个占位,不管图片是否加载完成页面总高度固定的。而safari就不同,图片没加载成功时高度是0svg

图片没加载成功时高度是0。哇长见识了。code

这时回想到以前在safari上的那个scroll bug,在查阅相关资料后就能够得出结论了:router

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。get

这个scrollView有什么用的?其实就是为了给其一个弹弹乐的效果(但确实用户体验不错)。it

当子元素是某个媒体格式时,好比img、object(svg)等,safari在加载完成以前是不会在计算在layout以内的,也就是高度为0,则子元素的高度就必定小于父元素的高度,safari不会给父元素一个原生的scrollView。

解决方法

反其道而行之。当出现这种问题的时候,给子元素一个包裹元素,包裹元素设置一个min-height大于父元素的高度,让父元素有scrollView。当子元素加载完成时,将包裹元素撑开,父元素即可以自由滚动了。

相关文章
相关标签/搜索