iOS 兼容到底有多难
同一个「输入面板贴着键盘弹起来」的效果,安卓上一行配置,iOS 上折腾了一整天。说说 iOS Safari 在键盘、聚焦、滚动上的几个特性,以及为什么它们凑在一起就格外难缠。
备注
本站手机评论区做了一个 B 站式的输入面板:点一下评论栏,面板从底部弹起、贴着键盘。安卓上一行配置就搞定了,iOS 上前后改了三版、十几个提交,最后还留了一处没修。这篇不讲过程,只讲 iOS 到底哪里特殊。
安卓:一行配置
安卓 Chrome 允许网页选择「键盘弹出时把页面挤矮」。在 viewport 里加一句 interactive-widget=resizes-content,键盘一出来,页面就缩到键盘上方,面板写个 bottom: 0 自然贴住键盘,不需要任何 JS。
iOS 没有这个开关。
iOS 的几个特性
| 特性 | 表现 | 对开发的影响 |
|---|---|---|
| 键盘只盖住页面,不挤小页面 | 页面布局纹丝不动,键盘直接压在上面 | CSS 的 fixed、sticky、视口单位都以「没被挡住的完整页面」为准,CSS 永远不知道键盘在哪,只能用 JS 读 visualViewport 去算 |
| 聚焦输入框会自动滚动 | 每点一个框,iOS 都要把它挪到可视区域中间,哪怕它本来就看得见 | 页面上任何「贴着某处」的东西都会被带着晃,而且手指点、键盘上的上下箭头、程序里调 focus() 都会触发,拦不全 |
| 字号小于 16px 的输入框一聚焦就放大 | 整页被放大,还能被拖着走 | 要么所有输入框字号 ≥ 16px,要么想办法关掉;常见的 maximum-scale=1 在 iOS 版 Chrome 上会把双指缩放也禁掉 |
| 键盘弹出时可视区域能被拖动 | 页面明明锁了滚动,手指一划照样动 | overflow: hidden 拦不住,得用 JS 拦触摸,或者把整页钉死 |
| 底部工具栏下面不画固定元素(iOS 26) | 固定在屏幕上的背景到工具栏上沿就断了 | 网页这边基本绕不过去,只能让露出来的那截颜色别太突兀 |
| 只有真机上才会出现 | 电脑浏览器、手机模拟器里一切正常 | 每改一次都得在 iPhone 上测一轮,排查只能靠在页面上打日志、截图 |
这些特性单独拿出来都还好办,难在它们会叠在一起:为了让面板贴住键盘,得用 JS 追着键盘位置走;可每次聚焦输入框,iOS 都会先把页面挪一下,JS 要等它挪完才追得上,面板就「被带走、再被拨回」,看着就是抖一下。去拦聚焦,又发现入口不止一个;去锁滚动,又发现 overflow: hidden 锁不住。
我们最后怎么收场的
拦不全,就别跟它对着干。iOS 上面板不再贴键盘,改成贴屏幕顶部往下展开,不用 JS 追;面板开着时把整个页面钉死,让 iOS 没得滚。其余平台照旧贴键盘。
判断「是不是 iOS」用的是一个只有 iOS 浏览器认识的 CSS 属性 -webkit-touch-callout,CSS 和 JS 两边都按它分开处理,不去解析浏览器的标识字符串。
最后留了一处没修:没登录时面板里有四个框,正文框在最下面,切到它时 iOS 还是会把面板挪一小段(约 22px)。能修,但又得再上真机测一轮,换来的只是没登录时少动一下,就停在这儿了。
为什么没人修
不是没人提。WebKit 有个「键盘弹出时视口机制失灵」的 bug 从 2018 年开到现在;谷歌的工程师也去 WebKit 那边提议过「让网页可以选择被键盘挤小」,至今挂着「需要表态」,苹果没回应。Chrome 和 Firefox 都在往前走,Safari 一直没跟进。
所以在可见的将来,iOS 上想让东西贴住键盘,还是只能写 JS,还得和它的自动滚动周旋。
参考
| 资料 | 说的是什么 |
|---|---|
| WebKit Bug 191204 | 键盘弹出时视口机制失灵,2018 年至今未修 |
| WebKit Bug 259770 | Safari 未实现 interactive-widget |
| WebKit standards-positions #65 | 「让网页选择被键盘挤小」的提议,苹果未表态 |
| MDN:Visual Viewport API | 键盘缩小的是可视视口,不是布局视口 |
| Rick Strahl:Preventing iOS Textbox Auto Zooming | 16px 与 maximum-scale 的取舍 |
评论
评论加载中……