前言
在做活动页的时候,第一页需要整屏显示,使用了 100vh
来作为第一页的高度,但在 ios safari 中效果却不是我所期望的那样。遂写篇博文来记录下问题的产生和解决及原因。
存在的差异
首先 100vh
在 Chrome 中模拟手机视图是正常的,如下:
在安卓真机 UC Turbo 显示也是正常的:
但在 ios safari 中,底部被 safari 的菜单栏挡住了:
出现的原因
这个问题出现的原因是:Safari 故意这样设计的,为此还专门做了很多的处理,因为它可以防止出现一些其他的问题。具体参见 Benjamin Poulain 回答的 bug 清单 ,其大意是:Safari 在滚动时可视高度会动态变化,如果在滚动的过程中更新 css 的视口高度,则会在滚动的过程中触发重新布局,这样做的话是非常糟糕的。
Safari 在向下滚动的过程中,顶部的工具栏和底部的菜单栏会隐藏,这样一来页面的视口高度就会发生改变。此时 safari 有两个选择:第一个是在视口高度变化时动态的更新 css 的视口高度,但这样做页面会在高度变化的时候重绘回流,重新布局,不仅会影响滚动的性能,还会影响交互体验。第二个则是在变化前的小视口和变化后的大视口来做为一个统一的视口,显然 Safari 的开发人员选择了大的视口作为标准视口,这样就会出现上面提到的问题:css 中设置高度为 100vh
时,底部的菜单栏会挡住一部分页面,但却避免了更多的问题。
解决方案
对于上面的这个问题,目前来说,比较完美的方案就是利用 window.innerHeight
在 resize
事件中动态的设置高度,对于使用 vh
来说,可以使用 window.innerHeight
配合 css 的自定义属性(变量)来适配。
如在 vue 中:
1 | mounted() { |
这样一来,在 css 中便可以这样写:
1 | .page { |
使用第三方库
推荐一个解决类似问题的 npm 库 vh-check
1 | npm install vh-check |
main.js:
1 | import vhCheck from 'vh-check' |
css:
1 | .page { |
vh-check 的核心原理也是上面所说的 window.innerHeight
结合 css var()
最后页面在 safari 中的表现总算比较正常了,此类问题,目前来说没有完美的方案,姑且算是比较完美吧。