iOSのSafariでwindowのresizeイベント直後に正常なwidthとheightが取得できない
PWAに対応したアプリ開発で、PCやAndroidのブラウザでは問題なく動作するのに、iOSに搭載されているブラウザのみ正常に動作しないといったことがありました。
目次
- やりたかったこと
- ダメだった対応
- 正常に動作した対応
- 余談
やりたかったこと
やりたかったのは、画面のサイズが変更されると、canvasに出力しているオブジェクトの位置を画面中央に寄せる、といったことで、windowのresizeイベントで、横と縦のサイズを取得して表示位置を変えていました。
PCだけでなく、Android端末でも動作し、スマートフォンの縦向きや横向きも正常に検出できていたので問題ないと思っていたら、最後の最後で、iOSで正常に動作しなかった、という流れになります。
実行しようとしたコードを簡単に示すと以下の通り。
window.addEventListener("resize", handleResize);
function handleResize(event) {
console.log(window.innerWidth);
console.log(window.innerHeight);
}
なんの変哲もない単純なイベント処理です。(実際にはcanvasに対してのアップデート処理が記述されている)
ですが、iOSで上記のresizeイベントを実行すると、正常なウィンドウサイズが取得できずに、「縦 > 横 > 縦」と向きを切り替えたら、表示がおかしくなってしまいました。
上記の画像は、本来であれば、画面いっぱいにオブジェクトが描画されるはずですが、一度横にしてしまった後は、canvasエリアが画面中央より少し下までとなって(点線赤枠のエリア)、その後は何度やってもこのような状態のままとなります。
この問題の原因を調査すると、最初に述べたように、windowのresizeイベントで「縦から横」または「横から縦」になった時の処理で、変更後の「window.innerWidth」と「window.innerHeight」が正常に取得できていませんでした。
ちなみにPCのChromeブラウザからF12でデベロッパーツールを開いて、表示モードをスマートフォンにした後、iOS系の端末を選んで動作確認した場合は、上記のような問題は発生しません。
ダメだった対応
「resize」イベントがダメであれば、端末の向きが変わったタイミングで発火する「orientationchange」イベントなら、と思って試してみました。
window.addEventListener("resize", handleResize);
window.addEventListener("orientationchange", handleResize);
function handleResize(event) {
console.log(window.innerWidth);
console.log(window.innerHeight);
}
ですが、残念ながら、この対応では改善しませんでした。
正常に動作した対応
何度か確認すると、端末の向きが変わった後のサイズではなく、変更前のサイズを取得していたのようなので、setTimeout()を使ってwindowオブジェクトからサイズを取得するタイミングを遅らせてみました。
window.addEventListener("resize", handleResize);
function handleResize(event) {
setTimeout(function(){
console.log(window.innerWidth);
console.log(window.innerHeight);
}, 200);
}
結果は良好で、これまでは崩れていた画面が、縦向きでも横向きでも正常に表示されるようになりました。
縦向き
横向き
詳しい理由は不明ですが、おそらく向きが変更されるタイミングと、windowオブジェクトの更新のタイミングが同期されておらず、windowオブジェクトの更新が間に合っていないのが原因だと思います。
余談
最近、Webサイトの作成でPCだけでなく、モバイル端末(AndroidやiOS)のブラウザでも動作確認するようにしているのですが、ちょっと手の込んだものを作ると、iOSの対応で躓くことが多いです。
思えばモバイルアプリ開発でCordovaに手を出した時も、iOSの対応でかなり時間を削られたような...
なんだか最近、iOSがモバイル界のIEのような位置づけに思えてきました。