Vue.jsでモバイルブラウザで全画面表示するには?

現象

HTML要素を全画面表示したい時についこのようにしてしまいがちです。

width = 100vw;
height = 100vh;

vwとはvhというのはViewportWidthとViewportHeightの略です。詳しくは「CSS には vw, vh, vmin, vmax という単位がある」の記事を読んでください。

Safariの画面の下部には戻る・進むなどのボタンがあるステータスバーがあります。 この 100vhで高さを指定すると、ステータスバーの後ろ側にまで要素が表示されてしまいます。

こちらの記事「いくつかのモバイルブラウザーではViewportの高さが実際の可視領域の高さより大きな数値になってしまう – Viewport height is taller than the visible part of the document in some mobile browsers」にこの現象について詳しく解説されています。

どうも Appleはこの不具合を修正するつもりはなく、Googleも最初は100vhはステータスバーを含まない高さだったのが、互換性のためにAppleの不具合を意図的に採用したとのことです。

現在ベストと考えている解決策

高さの指定方法

height = 100vh で指定しているCSSを下記のように書き換えてください。CSSの変数定義 var と計算calcにより height を指定します。ただしこの指定が使えない古いブラウザーのために height = 100vh の記述は残します。

height: 100vh;
height: calc(100 * var(--vh, 1vh));

この意味は、変数 --vh を初期値 1vh で定義して、高さを、--vh x 100 で求めています。つまり heightの初期値を 100vh で定義しています。

次に、JavaScriptで、高さを再計算します。可視領域の高さのピクセル数を innerHeight で求めます。そして100で割り、画面の高さの1/100のピクセル値を 変数 –vh に代入します。 そうすると先ほどのCSSから、height が、画面の高さの1/00のピクセル値 –vh x 100となり、ちょうど画面の高さになります。

const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty("--vh", `${vh}px`);

この記事を書きながら、CSSではvar(--vh,100vh) として、JavaScriptでは、`setProperty(“–vh”, `${window.innerHeight}px`);`でも動くんじゃないかという気がしてきましたので、だれか試してみてください。

どのタイミングJavaScriptを実行すべきか?

ここまでは、HTML5の問題でしたが、、ここから先は、Vueでの実装の話になります。

基本的には、mountされた後に実行される処理なので、mounted に記載してみました。この場合、初回はステータスバーの裏に表示されてしまうがリロードすると意図した表示になるとか、リロードを繰り返すとたまに、ステータスバーの裏に表示される不具合が発生しました。

VueのmountedのAPIドキュメントによると

mounted は 全ての子コンポーネントもマウントされていることを保証しないことに注意してください。ビュー全体がレンダリングされるまで待つ場合は、 mounted の代わりに vm.$nextTick を使うことができます。

Vue.js APIドキュメント

という記載がありました。ビュー全体がレンダリングされるのを待ってから先ほどの処理を以下のように実行するようにしました。

mounted() {
  this.$nextTick(function () {
    const vh = window.innerHeight * 0.01;
    document.documentElement.style.setProperty("--vh", `${vh}px`);
  });
}