原生应用的键盘感知布局会保证:软键盘弹出时,当前输入框自动滚入视野,没有任何东西被遮住。可到了 WebView 里,这份保证没了。WebView 在输入法(IME)出现时不会独立缩放可视视口;页面看不到键盘的几何信息;在 Android 与 iOS 上,用户正在输入的输入框常常被遮住。登录与支付表单变成了盲盒。宿主自有 runtime 提供键盘感知桥——宿主把输入法矩形报告给页面,让当前输入框始终可见。
WebView 看不到键盘
在 Android 上,Chrome 108+ 改变了键盘处理方式:浏览器只缩放可视视口、保持布局不变(resizes-visual)。但 WebView 被明确排除在这次改动之外。Chromium 一个至今未关闭的缺陷报告(issue 40287394)确认:WebView「无法让可视视口独立于布局视口缩放」,而且 Virtual Keyboard API 在 WebView 里根本不工作——boundingRect 被清零、geometrychange 事件从不触发。于是,adjustResize 会让整个布局跳动;adjustPan 会把布局上移但顶部被裁掉;而页面对键盘在哪儿毫无可靠信号。
iOS 同样把输入框藏起来
在 iOS 上,WKWebView 不会在键盘出现时自动把当前输入框滚入视野,而 visualViewport API 在不同版本间表现不一致。结果一样:用户正在输入的输入框落在键盘背后,页面既看不到键盘的尺寸与位置,也就无从把它推到前面。
输入框被遮住时,什么会崩
- 登录静默失败。 密码框被键盘挡住,用户盲打、提交错误凭证。
- 支付卡住。 卡号与验证码输入框被遮,结账流程走不下去。
- 布局跳动。
adjustResize让整页回流,sticky 与 fixed 元素错乱。 - 版本轮盘赌。 WebView 139+ 现在会在键盘弹出时缩放可视视口——但实测 resize 事件会清掉输入框焦点、再次隐藏键盘。
- 没有一致 API。
dvh单位只在较新引擎上有效;老 WebView 仍把键盘区域算进100vh。
runtime 解法
宿主自有 runtime 接管键盘。宿主在原生层监听 IME 的显示/隐藏,算出键盘矩形,把它作为键盘 inset 信号桥接给页面。页面随后把当前输入框保持在可见区域内——滚入视野或依据 inset 驱动布局——而不依赖引擎那不可靠的缩放。一套行为,覆盖每台设备、每个系统版本。
| 维度 | WebView | 宿主自有 runtime |
|---|---|---|
| 键盘几何信息 | 页面不可见 | 桥接报告 IME 矩形 |
| 可视视口缩放 | 不独立(Android) | 宿主驱动,一致 |
| iOS 输入框 | 不自动滚动 | 宿主滚入视野 |
| adjustResize 副作用 | 布局跳动 | 无——inset 感知 |
| 跨版本行为 | 随 WebView 版本崩 | 稳定 |
| 输入焦点 | 某些缩放下丢失 | 保留 |
原生应用绝不会让键盘吞掉输入框。原生 WebView 经常如此。runtime 把键盘放到页面看得见的地方——也让输入框回到用户看得见的地方。
参考来源
- Chromium Issue Tracker — WebView 无法让可视视口独立缩放 — 至今未关闭;Virtual Keyboard API 在 WebView 不工作。
- Android Developers — 理解 WebView 中的窗口边衬区 — WebView 如何接收键盘 inset。
- Chrome for Developers — 视口缩放行为(Chrome 108+) — WebView 始终没拿到的 resizes-visual。
- 荣耀 — Android 17 适配指南(WebView 139 键盘 + 焦点缺陷) — resize 清焦点、隐藏键盘。
- MDN — Visual Viewport API — 本该被键盘缩放的那个视口。