ダークサイドにようこそ!

限界クリエイターのブログ

【Three.js】iOS の Safari にてスクロール時にアドレスバーの有無で背景の描画が上下してしまう問題に対応する

自分はWebポートフォリオの背景にThree.js で点群ビジュアルを描画しているのですが、これはウィンドウのresizeイベントが呼ばれるたびにレンダラーのサイズ変更や3D空間におけるカメラのアスペクト比を調整するようになっています(ICS MEDIA の記事も参照)。ただiOSSafari でスクロールしていると唐突にアドレスバーが出たり消えたりすることがあって、その度に背景がリサイズ処理され描画内容が上下にカクっとずれてしまうのです(特にページの最下部到達時に起きることが多い)。これが地味にウザいです。そもそもこれがズレの原因と気付くまで時間かかりました。

 

アドレスバーが出てない(縮小されている)ときはこんな感じです。iOSSafari)のバージョンで微妙に仕様が異なるようです。上の写真はiOS17.1の場合。ネットで調べたりChatGPTに聞いても良さげな解決法が見つからなかったので、自分なりに暫定対応してみました。

 

具体的には「window.outerHeight」を使用します。window.innerHeight はコンテンツ表示領域の高さであるのに対し、window.outerHeight はアドレスバーなども含めたブラウザの高さを取得できます。後者はアドレスバーの有無で値が変わらないので、この値が変わった場合にのみThree.js のリサイズ処理を加えればとりあえず大丈夫そう。PC側のツールバーの有無でもリサイズされなくなっちゃいますが。

さらにダメ押しでウィンドウ横幅のサイズが異なる場合もリサイズするようにしました(スマホを縦→横向きにしたとき何故かこちらの条件が入ってないとリサイズされませんでした)。以下はコードの例。

setSize(){
        this.size = {
            windowW: window.innerWidth,
            windowH: window.innerHeight
        }
        this.windowOuterH = window.outerHeight;
}

 

resize(){
        if(window.outerHeight != this.windowOuterH || window.innerWidth != this.size.windowW){
            this.setSize();
            this.camera.aspect = this.size.windowW / this.size.windowH;
            this.camera.updateProjectionMatrix();
            this.renderer.setSize(this.size.windowW, this.size.windowH);
        }

}

 

以上です。ちなみにWebポートフォリオのコードはGitHub にて公開してます。アドレスバーの有無に限定した処理ってわけではないのですが、とりあえずスマホ触ってる時のウザい感じが解消できて良かったです。Three.jsのみならずリサイズ系のイベント処理を入れている場合は役に立つかも。Safariはマジで謎な挙動が多すぎる。

 

参考。逆にぱかぱかリサイズして欲しい場合はCSSで100dvhとか使えるのかも。

www.javadrive.jp

stackoverflow.com

 

その他の記事。

hahaeatora.hateblo.jp

hahaeatora.hateblo.jp

hahaeatora.hateblo.jp