generated at
Visual Viewport API

スクリーンキーボードを開いた後の画面サイズが取得できる、webブラウザのAPI
主にiPhone/iPadで、スクリーンキーボードの上にツールバーやステータスバーを実装するのに使う
iOSはスクリーンキーボードを開いても window.innerHeight が変化しない
position: fixed で画面の下端にくっつけている要素がキーボードで隠れてしまう
キーボードを背景透過させてwebページがぼけて見える仕様のせい
ボケすぎてて何も見えないけど

Mobile Keyboard Toolbarで使おうと思ったけどだめだった
iOSでスクリーンキーボードの上、画面下端にツールバーをくっつけたかった

Androidではまったく不要
CSSの position: fixed bottom: 0 でいい
Androidはスクリーンキーボードを開くと window.innerHeight が縮むので


ドキュメント


対応ブラウザ
iOS 13から使える


API
visualViewport.height visualViewport.offsetTop
スクリーンキーボードを除いた大きさと位置が取得できる
window.height window.offsetTop と同じような感じ
CSSではなくJavaScriptで値を取得し、要素を移動させなければならない
Reactだとこんな感じだが
js
const offsetTop = visualViewport.height - 40 + visualViewport.offsetTop; const style = { transform: `translate(${visualViewport.offsetLeft}px, ${offsetTop}px) scale(${1/visualViewport.scale})` // CSS書いて } return ( <div className='bottom-toolbar' style={style}> // styleにセット
画面スクロールなど、適切なイベントを使ってstyleを再セットし続け、ずっとrenderしなおす必要がある


調査した
Androidはすばらしい出来
全ての visualViewport の値がfloatでリアルタイムに更新される
iOSはひどい
textareaにカーソルを入れ、スクリーンキーボードを表示している間は
スクロールを完全に止めるまで、scrollイベントが発火しなくなる
visualViewport.offsetTop の反映が遅れる
0.5刻みで、Androidより精度が低い
window.scrollY は遅延がない
しかしこちらはIntegerなのでガタガタになる
なぜ1px未満の細かいスクロールができる端末で、開発者が取得できる座標系が整数なんだろう?
Androidは window.scrollY もfloatなのに
特にiOS safariでは、上下スクロールによってアドレスバーの高さが変化するのだが
それが visualViewport.height に反映されるタイミングが一瞬遅い
スクリーンキーボードを開いていない場合は反応が速い
iPad
Safari Chrome共通
visualViewport.offsetTop の反映が遅い。iOSと同じ
Chrome
スクリーンキーボードの上のパスワードボタンの高さが visualViewport.height に含まれていない
これはSafariでは問題ない

結論
こういうのはiOSでは絶対に作れない
スクリーンキーボードの上にツールバーを常に表示し
上下スクロールしてもスクリーンキーボードにぴったりくっついてくるUI
やるならこう
スクロール中は非表示
スクロールが終わったらツールバーを表示する
windowのscrollやresizeイベントを見て、500 msecぐらい静かであったらスクロール完了と見なす
visualViewport.height visualViewport.offsetTop を使って表示位置を計算する
Mobile Keyboard Toolbarではとりあえずこうする予定shokai
iOSのために作られたAPIだが、iOSはまともに実装されていない
Androidではまったく必要の無いAPIだが、完璧に実装されている