iPhoneでも全画面表示(iOS15への対応)


はじめに

以前の投稿からの iOS15 への対応となりますので、こちらもご参照ください。
また、参考にさせていただいてるkrpanoがバージョンアップし、iOS15でのフルスクリーン表示に対応されました。

やってみるしかない

サンプルコード

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover" />
<style >
    :root { --sat: env(safe-area-inset-top); --sar: env(safe-area-inset-right); --sab: env(safe-area-inset-bottom); --sal: env(safe-area-inset-left); }
    * { margin:0; padding:0 }
    html, body { height:calc(100% + var(--sab)) }
    body { font-family:sans-serif; color:#fff }
    #fs { position:absolute; display:none; justify-content:center; align-items:center; width:100%; height:100%; background-color:RGBA(0,0,0,0.8) }
    #fsd { position:absolute; z-index:-2; width:100%; height:100vw; touch-action:pan-y }
    #container { position:fixed; z-index:1; width:100%; height:100%; background-color:#b1dff7; touch-action:none; transform:translateZ(0) }
    #container p { position:absolute; width:40px; height:40px; background-color:#fff }
    #container p:nth-child(1) { left:5px; top:5px; margin-left:var(--sal) }
    #container p:nth-child(2) { top:5px; right:5px; margin-right:var(--sar) }
    #container p:nth-child(3) { right:5px; bottom:5px; margin-right:var(--sar); margin-bottom:var(--sab) }
    #container p:nth-child(4) { bottom:5px; left:5px; margin-bottom:var(--sab); margin-left:var(--sal) }
    @media ( orientation:landscape ){
        #container p:nth-child(n+3) { margin-bottom:0 }
    }
</style>
</head>
<body>
    <div id="container">
        <p></p>
        <p></p>
        <p></p>
        <p></p>
    </div>
    <script>
        let _ua = navigator.userAgent.toLowerCase(),
            _container = document.querySelector('#container');

        if ( (/iphone/.test(_ua)) && !(/crios|edgios/.test(_ua)) ){
            var _fs = document.createElement('div'),
                _fsd = document.createElement('div');
            _fs.id = 'fs';
            _fs.innerHTML = '&#8593;&nbsp;SWIPE';
            _container.appendChild(_fs);
            _fsd.id = 'fsd';
            document.body.insertBefore(_fsd, _container);

            document.addEventListener( 'DOMContentLoaded', fs_display );
            window.addEventListener( 'resize', fs_display );

            function fs_display() {
                if ( window.orientation == 0 ) {
                    _container.style.height = '100%';
                    _fs.style.display = 'none';
                } else {
                    _container.style.height = '100vh';
                    if ( screen.width - window.innerHeight <= 20 ) {
                        _fs.style.display = 'none';
                        _fsd.style.zIndex = '-2';
                    } else if ( screen.width - window.innerHeight > 20 ) {
                        _fs.style.display = 'flex';
                        _fsd.style.zIndex = '2';
                        window.scrollTo(0, 0);
                    }
                }
            }
        }
    </script>
</body>
</html>


構造(変更箇所)

HTML
<body>
    <div id="fsd"></div>
    <div id="container">
        // Your contents.
        <div id="fs">&#8593;&nbsp;SWIPE</div>
    </div>
</body>

↑ SWIPEを表示するdiv#fsdiv#container内に、スワイプする為の空要素としてdiv#fsddiv#container外に分けた構造とします。

CSS
html, body { height:calc(100% + env(safe-area-inset-bottom)) }
#fs { position:absolute; display:none; justify-content:center; align-items:center; width:100%; height:100%; background-color:RGBA(0,0,0,0.8) }
#fsd { position:absolute; z-index:-2; width:100%; height:100vw; touch-action:pan-y }
#container { position:fixed; z-index:1; width:100%; height:100%; background-color:#b1dff7; touch-action:none; transform:translateZ(0) }

div#containerposition:fixedとし、html,bodyにはheight:calc(100% + env(safe-area-inset-bottom))div#fsdheight:100vwを設定します。
div#fsdtouch-action:pan-ydiv#contanertouch-action:noneとし制限をかけるのは変わりません。

div#fsdheight:100vwとすることで、portrait時には邪魔にならずlandscape時にはスワイプする為の要素となります。

div#containertransform:translateZ(0)を設定することで、position:fixedでも非表示領域をレンダリングしてくれます。

設定からの文字サイズ変更には対応しておりますが、ブラウザ側での文字サイズ変更には対応しておりません。


制御(変更箇所)

JS
let _ua = navigator.userAgent.toLowerCase(),
    _container = document.querySelector('#container');

if ( (/iphone/.test(_ua)) && !(/crios|edgios/.test(_ua)) ){
    var _fs = document.createElement('div'),
+       _fsd = document.createElement('div');
    _fs.id = 'fs';
    _fs.innerHTML = '&#8593;&nbsp;SWIPE';
    _container.appendChild(_fs);
+   _fsd.id = 'fsd';
+   document.body.insertBefore(_fsd, _container);

    document.addEventListener( 'DOMContentLoaded', fs_display );
    window.addEventListener( 'resize', fs_display );

    function fs_display() {
        if ( window.orientation == 0 ) {
+           _container.style.height = '100%';
            _fs.style.display = 'none';
        } else {
+           _container.style.height = '100vh';
            if ( screen.width - window.innerHeight <= 20 ) {
                _fs.style.display = 'none';
+               _fsd.style.zIndex = '-2';
            } else if ( screen.width - window.innerHeight > 20 ) {
                _fs.style.display = 'flex';
+               _fsd.style.zIndex = '2';
+               window.scrollTo(0, 0);
            }
        }
    }
}

div#containerはportrait時height:100%、landscape時height:100vhとなるよう制御し、div#fsdの表示・非表示をz-indexで制御しコンテンツの高さを保つことで上部バーの再表示を防ぎます。

window.scrollTo(0, 0)でスクロール状態をリセットすることで、上方向スワイプのみの操作でバーを隠せるようになりました。

まとめ

下部セーフエリア周りの仕様が、、safe-area-inset-bottomのサイズと実際のタップ範囲が違う、、のか、、ツールバーのサイズは1rem + env(safe-area-inset-bottom) ということらしく、タップ範囲となるっぽいのだが、、下のタブバー表示でツールバー非表示にするとタップ範囲は併せて狭くなってくれるの、、、だが、上部アドレスバー表示の時は変わらない、、、んだ。