【JavaScript】iOSでposition:fixedな要素をキーボード上に押し上げる
やりたいこと
モバイルだとテキストボックスなどにfocus
するとバーチャルキーボードが表示されるが、iOSの場合position:fixed
で配置した要素はこれによって隠れてしまうことがある。
そこで上記のYouTubeネイティブアプリのように、position:fixed
な要素をキーボードの上に添えながら押し上げて表示させたい。
解決法
CSSのみだと厳しいが、JavaScriptのvisualViewport
APIを利用することでお手軽に実現できる。
<body> <input type="text" /> <button>sample button</button></body>
button { width: 100vw; position: fixed; bottom: 0; left: 0; background-color: black; color: #fff; text-align: center; line-height: 50px; font-weight: bold; transition: bottom 0.3s;}
まずサンプルのレイアウトを作成する。
function registerPushupEvent() { if (!/iPhone|iPad|iPod/.test(navigator.userAgent)) return;
const button = document.querySelector("button");
visualViewport.addEventListener("resize", ({ target }) => { const keyboardHeight = window.innerHeight - target.height; const bottomValue = keyboardHeight === 0 ? "" : `${keyboardHeight}px`; button.style.bottom = bottomValue; });}
registerPushupEvent();
visualViewport
の基本的な使い方について、詳しくは下記記事で触れている。
【JavaScript】visualViewportでスマホのバーチャルキーボードの出現を検知し高さを取得する
これで無事、キーボードに押し上げられる形で対象要素が動いてくれた。(なぜかXcodeのシミュレーター上ではresize
イベントの発火までにラグがあったが、実機だと想定通りに動作した)
その他に試したこと
キーボードの高さの決め打ち
調べたところどうやらシェア率の高いiPhoneだと仮想キーボードの高さが270px
辺りらしいので、キーボードの高さを決め打ちして動かすという方法でもできなくはない。
function registerPushupEvent() { if (!/iPhone|iPad|iPod/.test(navigator.userAgent)) return;
const input = document.querySelector("input"); input.addEventListener("focus", () => (button.style.bottom = "270px")); input.addEventListener("blur", () => (button.style.bottom = ""));}
registerPushupEvent();
しかし全デバイスでキーボードの高さが同一ではないので、配置がズレてしまうことを容認できる場合のみにしか使えない。ゆえにこの方法は断念した。
VirtualKeyboard APIの利用
VirtualKeyboard APIはその名の通り、ブラウザの仮想キーボードを制御するためのもの。
navigator.virtualKeyboard.addEventListener("geometrychange", ({ target }) => { const { height } = target.boundingRect;});
上記のように書くことでキーボードの高さを取得できるが、iOS16時点ではそもそもこのAPIがSafariに対応していないので無理だった。