关于 Safari 100vh 的问题与解决方案
最近在做一个移动端的 H5 项目 遇到了一个「有趣」的问题。假设有一页面布局如下
下方 50px 悬浮于底部 采用 fixed 布局 示例如下
div class container !-- height: 100vh - 50px -- div class page /div !-- fixed bottom, height: 50px -- div class tabbar TabBar /div /div script window.onload function () { const arr new Array(100).fill(0).map((_, index) index 1) const pageEl document.querySelector( .page ) const listEl document.createElement( div ) arr.forEach(item { const itemElement document.createElement( div ) itemElement.innerText item itemElement.className list listEl.appendChild(itemElement) pageEl.appendChild(listEl) /script
完整示例请看 CodeSandbox。
测试下来看似乎没问题 可当你使用 iPhone 的 Safari 浏览器打开此页面时 就会出现如下情况
截图中已滑动至页面最底部 然而 100 被 TabBar 部分挡住了 其他浏览器均能正常展示出来 。
我们知道 vh、vw 都是 CSS 中的一种相对长度单位 1vh 表示 viewport 高度的 1% vm 同理 。简单来讲 viewport 基本上是指当前文档的可见部分 因此 100vh 表示可见文档的最大高度。
可事实真是如此吗
在 Safari 浏览器中 100vh 如下图所示 出自
按上面所说 100vh 不应该是 viewport 可视区域的全部高度 为什么右图的高度会超出的呢
做个简图区分一下吧
所以 这就是为什么在 Safari 会被挡住一部分的原因。
吐槽一下 Safari 会是现代化的 IE 浏览器
是 bug 还是故意为之
可以详细地看下这篇文章 Viewport height is taller than the visible part of the document in some mobile browsers 然后文章作者给 WebKit 提了个 bug 其中 Apple 工程师 Benjamin Poulain 的回答如下
This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)
So, it s a feature, not a bug.
然而 并不是只有 Safari 是这样做的 比如 iOS 端 Chrome 浏览器表现与 iOS 端 Safari 一致... (⊙ˍ⊙)
尽管这并不是大多数开发者想要的 但很无奈 我们只能想办法去「修复」它 使得我们的网站在各浏览器表现一致。
方案一 使用 -webkit-fill-available
简单来说 -webkit-fill-available 就是自动填满剩余空间 详见 。这里使用另一个示例 来说明 -webkit-fill-available 的一些问题 如下
!DOCTYPE html html head meta charset UTF-8 / meta http-equiv X-UA-Compatible content IE edge / meta name viewport content width device-width, initial-scale 1.0 / title Document /title /head style padding: 0; margin: 0; text-align: center; body { min-height: 100vh; display: flex; flex-direction: column; /style body div style height: 100px; background: blue /div div style flex: 1; background: red /div div style height: 100px; background: green /div /body /html
以上示例 分别会有蓝、红、绿三部分 按预期结果 它们应该会占满整个可视区域 完整示例请看 CodeSandbox 而 Safari 中底部绿色部分会被挡住。然后我们添加在 body 添加上 -webkit-fill-available 看看
body { min-height: 100vh; min-height: -webkit-fill-available; display: flex; flex-direction: column; }
iOS 上的 Safari 中的表现是正常了 但是你会发现 Chrome 下红色区域没了 原因是 Chrome 84 起已不再支持 -webkit-fill-available 所以实际渲染如下
那么解决方法就是 针对 Safari 浏览器才设置 -webkit-fill-available 即可 这里利用到 support 和 -webkit-touch-callout 如下
body { min-height: 100vh; display: flex; flex-direction: column; supports (-webkit-touch-callout: none) { body { min-height: -webkit-fill-available; }
这样就 OK 了 Safari 和 Chrome 表现均如预期一致。这也是 postcss-100vh-fix 插件的解决方案。
然而 以上方案并不适用于这些情况 比如 height: 90vh、height: calc(100vh - 50px) 因此才有了方案二。
方案二 通过 CSS 变量计算 1vh 所表示的实际高度
思路
设置一个 CSS 变量 比如 --vh 然后通过 JavaScript 脚本动态设置 --vh 的值 然后使用时需兼容处理即可 比如 height: 100vh; height: calc(var(--vh) * 100) 。
实现如下
style :root { --vh: 1vh; /style script !(function (n, e) { function setViewHeight() { var windowVH e.innerHeight / 100 n.documentElement.style.setProperty( --vh , windowVH px ) var i orientationchange in window ? orientationchange : resize n.addEventListener( DOMContentLoaded , setViewHeight) e.addEventListener(i, setViewHeight) })(document, window) /script
使用 vh 时 需要这样兼容处理
.page { height: calc(100vh - 50px); height: calc(var(--vh) * 100 - 50px); }
有一个 react-div-100vh 库就是获取 window.innerHeight 然后将其值设置为容器高度实现的 然而这也是仅可处理 100vh 的情况。
至于使用哪一种解决方案 视乎实际情况而定吧
移动端 Retina屏border实现0.5px 首先来看一下造成Retina边框变粗的原因 其实这个原因很简单,因为css中的1px并不等于移动设备的1px,这些由于不同的手机有不同的像素密度。在window对象中有一个devicePixelRatio属性,他可以反应css中的像素与设备的像素比。
现在很多for Mobile的HTML5网页内都有快速滚动和回弹的效果,看上去和原生app的效率都有得一拼。 要实现这个效果很简单,只需要加一行css代码即可: -webkit-overflow-scrolling : touch;可用以...
相关文章
- 关于YiII框架的扩展memcache中set设置时间就get查询失效的解决方案(版本是1.1.20)
- Origin 坐标轴不见了解决方案
- Android ListView之checkbox滑动错位问题简单完美解决方案
- egg 执行 yarn start 失败的解决方案
- Vue - 最新网页 H5 分享到微信朋友圈 / 转发分享给朋友好友 / 分享到手机 QQ / 分享到 QQ 空间,Vue.js Nuxt.js 通用公众号页面解决方案(超级详细教程)
- 关于分页的解决方案收集
- iOS中CollectionView由于多次点击造成错误的解决方案
- 关于Android中设置闹钟的相对比较完善的解决方案
- 关于Android中设置闹钟的相对完善的解决方案
- 关于宝塔面板忘记密码的解决方案
- Xcode9.2打包图片显示异常解决方案
- 大数据架构和模式(三)——理解大数据解决方案的架构层
- 关于内层div设置margin-top不起作用的解决方案
- 【Release Notes】Kubernetes解决方案更新
- 关于Chrome字体模糊解决方案
- 这种口令解决方案可替代多因子验证
- 神州数码网真解决方案助山西电力信息高速化
- 【多服务场景化解决方案】让新闻“动”起来
- 关于Unity点击New创建新项目没反应的解决方案
- 几万字图文详解pptp实战全套解决方案及源码包括详细的安装、配置、使用,涉及服务器、移动Wi-Fi路由器、手机、电脑等设备,以及若干问题如连接成功无法上网、连接数量限制、动态注册用户问题等等
- 关于 ElementUI 通知组件 notification 重叠问题的解决方案