一个超级诡异的 iOS Safari `position: fixed` 失效问题

首发我的博客,两边同步更新。

先说需求。东家让我做个日历组件,在手机 Web 上用。组件的样式是这样的,很多地方都可以见到,比如南航国航的客户端。

《一个超级诡异的 iOS Safari `position: fixed` 失效问题》

看起来并不复杂,事实上也是,基本上顺顺利利的开发完成,准备交付。这里有个伏笔,开发中我按老习惯,使用桌面 Chrome,和实际生产环境不太一样。不过我自然要去真机上测试,结果一测问题就出来了。

因为组件需要全屏展示,所以我设置了如下的CSS:

.date-picker {
  position:fixed;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background-color: white;
  z-index:1024;
}

同时,对原本的 <input name="date">,我给它加上 readonly,避免弹出虚拟键盘。理论上,这样的就可以了。但实测时,不滚屏的时候,组件弹出时尺寸是准确的,盖满全屏;然则一旦滚屏,组件就会占据从页面最上方到当前最下面这截位置。大约相当于 position:absolte;top:0 的效果。

《一个超级诡异的 iOS Safari `position: fixed` 失效问题》
《一个超级诡异的 iOS Safari `position: fixed` 失效问题》
如图,可以看到组件占据了全屏,但实际是从页面最上面开始的,定位有问题。用桌面 Safari 调试也可以看出来它的高度是 968,远大于正常的 667。

这很诡异,上下左右全为0,是上古巨兽 IE6 都支持的做法。iOS Safari 虽然 Bug 多多,不应该连这个都有毛病啊。以 ios safari position fixed 为关键词 Google 之,结果 iOS Safari 历史不清白,当年 iPhone 刚出的时候的确有定位问题,于是虽有满屏的结果,但都不适用。

然后我想到找其它库,比如 Bootstrap,它的 Modal 组件也是类似的效果。但是怎么测都正常,于是我只好一个样式一个样式修改,仍然没有结果。

时间慢慢流逝,转眼已经凌晨2点了,就在我几欲放弃之际,突然发现,虽然组件弹出的时候定位有问题,但只要我点掉下面的完成,定位就会立刻恢复正常。

《一个超级诡异的 iOS Safari `position: fixed` 失效问题》
注意,就是那个“完成”。

问题至此已经明朗:在 iOS Safari 里,即使 <input> 设置了 readonly,它仍然可以获取输入焦点。获取输入焦点之后,虽然没有弹出虚拟键盘,但仍然是待输入状态。

此时页面各种交互都是正常工作的,比如点击、滚屏。唯独 position:fixed 定位有问题。点击“完成”离开输入状态,Safari 自动刷新页面元素,定位就正常了。

于是我在组件弹出后,自动 input.blur(),使其失去焦点,组件的尺寸便正常无误了。

总结

移动端 Web 开发总有各种各样稀奇古怪的问题。有些好解决,有些不好解决,比如这个问题,很难定位:

  1. 历史不清白,搜也搜不到

  2. 组件要求全屏,需要避免虚拟键盘,所以会改变默认行为

  3. 其它情况下都是好的

我能想到的方案,就是想办法,用所有能用的工具,排除掉所有其它问题,最终还是能搞出来的。

    原文作者:Meathill
    原文地址: https://segmentfault.com/a/1190000008450982
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞