R4.05.2visual viewport设计

移动浏览器的视口与键盘行为特殊

别名: 布局视口 · 可视视口 · 软键盘 · 100vh

概念解释

桌面浏览器里,窗口大约就是视口。移动浏览器把这件事拆成两块:布局视口(layout viewport)是 CSS 用来排版的那张纸,可视视口(visual viewport)是用户此刻看见的、会被双指缩放和输入法(IME)软键盘改变的那扇窗。地址栏升起落下、软键盘顶上来,可视视口在缩,布局视口未必一起缩。100vh 常常包含被浏览器壳盖住的那一段,position: fixed 的底栏会在键盘弹出时悬空、被顶起、或被键盘盖住——三种引擎三种结果。

它处理的是移动浏览器里「屏」这个词为什么不够用,不是标准与实现之间那些通用的控件分叉。在移动 Web 上把底栏按桌面的固定定位来做,等于假设只有一个视口。

机制

布局视口相对稳定,是为了让文档在缩放时不要整页重排;可视视口跟着用户的观察窗口走,是为了让放大后的那一块能被看见。软键盘是第三块占用:有的引擎缩小可视视口,让 fixed 底栏升到键盘上方;有的引擎把键盘盖在布局视口上,底栏仍停在文档底部,实际已经不可见;有的只在聚焦输入框时改 window.innerHeight。输入法还有候选栏,中文、日文输入时候选条会再吃一截高度,英文二十六键与中文九键的高度也不一样。

地址栏的显示与隐藏同样改写可视高度,而且是滚动方向的副作用,不是应用能调用的开关。于是「屏幕底部」在移动浏览器里至少有三个候选:布局视口底、可视视口底、键盘上沿。设计如果只认其中一个,输入时的关键按钮就会落到另外两个上。双指缩放会让可视视口变成布局视口里的一个小矩形,此时 fixed 元素相对布局视口钉住,用户看见的是它被移出了当前窗口。

边界

桌面和带物理键盘的平板,软键盘不占视口,问题退化为窗口缩放与开发者工具停靠,不必用移动这套三视口模型。应用内 WebView 可以和系统浏览器约定不同的键盘策略,不能把 Safari 或 Chrome 的行为抄进壳里当事实。全屏独立应用(把 Web 装进原生壳并隐藏浏览器地址栏)仍可能弹出系统 IME,但少了地址栏这一层。横屏、分屏和折叠会改变两套视口的初始值,只在竖屏窄宽度上调过的底栏,横过来会再次错位。

怎么落地

  • 钉在底部的主操作按可视视口或键盘上沿来定位,不要用 100vh 当「看见的高度」;表单提交按钮必须在输入法打开时仍能被点到或被滚到。
  • 区分「文档底部」和「当前看见的底部」:阅读性底栏可以跟布局视口,输入时的发送/下一步必须跟可视视口。
  • 在中文输入法候选栏打开、地址栏展开、双指缩放三种条件下分别检查 fixedsticky 元素。
  • 验证:在系统浏览器里聚焦一个靠近底部的输入框,用中文输入法打字,看提交按钮、错误提示和自定义底栏是否被键盘或候选栏盖住、是否悬在键盘上方挡住候选、是否随地址栏跳动。三种引擎各做一次。任何一次要点两次才能点中提交,都说明定位钉错了视口。

延伸

  • 同组R4.05.1 标准行为与实现行为存在差距 · R4.05.3 渐进增强是应对差异的基本策略
  • 相邻C6.06 软键盘与屏幕占用 · C6.12 输入法候选
  • 站内检索visual viewport · layout viewport · virtual keyboard · IME

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/R4.05.2