position: fixed と height: 100vh を使って全画面の固定表示をした際、スマホだとアドレスバーなどブラウザのUIが重なって要素の一部見えなくなってしまうことがあります。
このUIが重なってしまうのを回避する方法についていくつか試してみます。
サンプルコード
モーダルを実装する例で試してみます。
まずは対応前です。
<button data-modal_top_link="modal-a">上付きモーダル</button> <div class="modal-top" data-modal_top_content="modal-a"> <div class="modal-top_box"> <button class="js-modalclose">閉じる</button> <ol> <li>上付きのモーダルコンテンツです上付きのモーダルコンテンツです上付きのモーダルコンテンツです</li> 〜 略 〜 <li>上付きのモーダルコンテンツです上付きのモーダルコンテンツです上付きのモーダルコンテンツです</li> </ol> </div> </div> <button data-modal_btm_link="modal-b">下付きモーダル</button> <div class="modal-btm" data-modal_btm_content="modal-b"> <div class="modal-btm_box"> <button class="js-modalclose">閉じる</button> <ol> <li>下付きのモーダルコンテンツです下付きのモーダルコンテンツです下付きのモーダルコンテンツです</li> 〜 略 〜 <li>下付きのモーダルコンテンツです下付きのモーダルコンテンツです下付きのモーダルコンテンツです</li> </ol> </div> </div>
data-modal_XXX_link 属性のついたボタンがモーダルを開くリンク、data-modal_XXX_content 属性のついた要素がモーダル要素で、それぞれのdata属性の値の一致するモーダルが開く想定です。
position: fixed; の位置指定をtopの場合とbottomの場合のそれぞれで試したいので、XXXの部分にはtop(top: 0;)とbtm(bottom: 0;)が入るようにしています。
次にCSSです。
モーダルを開く際に data-modal_XXX_content 属性に .is-showが付与される想定です。
.modal-top, .modal-btm { display: none; align-items: center; justify-content: center; position: fixed; left: 0; width: 100%; height: 100vh; background: rgba(0, 0, 0, 0.2); } .modal-top { top: 0; } .modal-btm { bottom: 0; } .modal-top.is-show, .modal-btm.is-show { display: flex; } .modal-top_box, .modal-btm_box { width: calc(100% - 30px); height: calc(100vh - 30px); overflow-y: auto; background: white; }
最後にJavaScriptです。
data-modal_XXX_link 属性をクリックした際に、対応する data-modal_XXX_content 属性に .is-showを付与します。
$(function() { $(document).on('click', '[data-modal_top_link]', function() { const target = $(this).data('modal_top_link'); $('[data-modal_top_content = ' + target + ']').addClass('is-show'); }); $(document).on('click', '[data-modal_btm_link]', function() { const target = $(this).data('modal_btm_link'); $('[data-modal_btm_content = ' + target + ']').addClass('is-show'); }); $('.js-modalclose').on('click', function() { $('[data-modal_top_content], [data-modal_btm_content]').removeClass('is-show'); }); });
これで簡単なモーダルが実装できましたが、スマホで見た際にブラウザのUIが要素の一部に重なっていました。
対応前のデモページ
iOS 15.7.1の場合は下記の通りで、上付きの場合は下部のアドレスバーが重なり、下付きの場合は上部が切れてしまっていました。
Android 11の場合も同様で、上付きの場合は下部が切れていて、下付きの場合は上部のアドレスバーが重なっていました。
次に対応方法ですが、1つ目はheightに100vhではなく100%を指定する方法です。
.modal-top, .modal-btm { display: none; align-items: center; justify-content: center; position: fixed; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.2); } .modal-top { top: 0; } .modal-btm { bottom: 0; } .modal-top.is-show, .modal-btm.is-show { display: flex; } .modal-top_box, .modal-btm_box { width: calc(100% - 30px); height: calc(100% - 30px); overflow-y: auto; background: white; }
position: fixed の要素にheight: 100% を指定した場合、ブラウザのUIを除いた範囲(アドレスバーなどが縮小や非表示になっている場合、その分範囲が広がる)が高さになるようです。
手持ちの端末で試した範囲ではアドレスバーなどが重なる問題は解消されていました。
2つ目はJavaScriptで取得して指定する方法です。
$(function() { $(document).on('click', '[data-modal_top_link]', function() { const target = $(this).data('modal_top_link'); $('[data-modal_top_content = ' + target + ']').addClass('is-show'); }); $(document).on('click', '[data-modal_btm_link]', function() { const target = $(this).data('modal_btm_link'); $('[data-modal_btm_content = ' + target + ']').addClass('is-show'); }); $('.js-modalclose').on('click', function() { $('[data-modal_top_content], [data-modal_btm_content]').removeClass('is-show'); }); }); $(window).on('load scroll resize', function() { $('[data-modal_top_content], [data-modal_btm_content]').css({ height: window.innerHeight }) });
window.innerHeightで高さを取得した上で、100vhを指定していた箇所にstyle属性で設定しています。
スクロール時やリサイズ時にも随時更新されるようにイベントも併せて設定しています。
JavaScriptで指定するデモページ
3つ目はJavaScriptで取得するところまでは前と同じですが、指定にCSSのカスタムプロパティを使用する方法です。
$(function() { $(document).on('click', '[data-modal_top_link]', function() { const target = $(this).data('modal_top_link'); $('[data-modal_top_content = ' + target + ']').addClass('is-show'); }); $(document).on('click', '[data-modal_btm_link]', function() { const target = $(this).data('modal_btm_link'); $('[data-modal_btm_content = ' + target + ']').addClass('is-show'); }); $('.js-modalclose').on('click', function() { $('[data-modal_top_content], [data-modal_btm_content]').removeClass('is-show'); }); }); $(window).on('load scroll resize', function() { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', vh+'px'); });
これで「–vh」でブラウザのUIを考慮した値を取得できるようになったので、CSSの高さ指定部分をカスタムプロパティを使った形に変更します。
.modal-top, .modal-btm { display: none; align-items: center; justify-content: center; position: fixed; left: 0; width: 100%; height: calc(var(--vh, 1vh) * 100); background: rgba(0, 0, 0, 0.2); } .modal-top { top: 0; } .modal-btm { bottom: 0; } .modal-top.is-show, .modal-btm.is-show { display: flex; } .modal-top_box, .modal-btm_box { width: calc(100% - 30px); height: calc(var(--vh, 1vh) * 100 - 30px); overflow-y: auto; background: white; }
JavaScriptとカスタムプロパティで指定するデモページ
position: fixed を指定した要素の場合は基本的にheight: 100%での対応で大丈夫そうですが、実装の仕様などに応じて方法を適宜選択ください。
コメントが承認されるまで時間がかかります。