IE11とiPhon対応 フッタを画面下に表示

コンテンツの量が少ない場合や、解像度の高いディスプレイでみた場合、
いわゆるスクロールバーが出ない状態では、フッタが上にせり上がった状態になり、下へ隙間ができます。

この解決方法でよく見かけるCSS対策がこの2つ。

  • bodyにdisplay: flex; を設定する
  • htmlとbodyへmin-height: 100%;を設定する

しかし、これらを安直に設定してみたところ
Internet Explorer 11とiPhoneのSafariでつまづいたので
ポイントをまとめてみました。

See the Pen Footer on bottom of page by webdev (@webdev-jp-net) on CodePen.0

スマートフォン確認用:
Footer on bottom of page サンプル

IEでmin-heightが効かない問題

IEはdisplay: flex;min-heightが効かない仕様です。
このように設定して、できた!と思っていたら、IEでは効いていませんでした。

html {
  min-height: 100%;
}
body {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}
body > footer {
  margin-top: auto;
}

IE対策は flexの入れ子

html {
  min-height: 100%;
}
body {
  display: flex;
}
body > #page {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}
#page > footer {
  margin-top: auto;
}

display: flex; が効いたbodyの中にdivを追加して、
flexboxを入れ子にするとIEでもhtmlと同じ高さ(表示範囲の高さ)までdivがフィットしてくれます。

入れ子にしていると、bodyにはmin-heightを設定していなくても大丈夫です。

iPhoneのSafariは100vhが画面外にはみ出す

iPhoneのSafariは、内容が少なくスクロールがない場合は
ブラウザの底辺に表示されているメニューバーがせり出しています。

この影響で、実際に見えている範囲の高さは
100vh - メニューバーの高さ
になっていて、min-height: 100vh;を設定していると
フッタが見切れて常にスクロールできるようになってしてしまいます。

表示範囲の高さは window.innerHeightで取得

2019年10月現在は、残念ながらスタイルシートだけではメニューバーに影響されない画面の高さを取得することができません。
iPhone Safariでもフッタを画面下ぴったりに表示させるなら、JavaScriptで調整します。

まず、フッタの直接の親となる要素(例では#page)には
スタイルシートでmin-height: 100vh;を設定しておきます。

body > #page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

iPhone Safariの表示範囲の高さはwindow.innerHeightで取得できます。

var $page = document.getElementById('page');
if ($page.clientHeight != window.innerHeight)
  $page.style.setProperty('min-height', window.innerHeight + 'px');

#pageのclientHeight > window.innerHeight
なら、表示範囲の高さが100vhと一致していないことになるので
min-heightの値をwindow.innerHeight(=表示範囲の高さ)に書き換えています。

このとき、カクつく違和感を軽減するため
スタイルシートでmin-height: 100vh;を設定するついでに
transitionmin-heightも設定すると
アニメーションしながら縮むので自然になります。

body > #page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  transition: min-height .2s;
}

スマホを回転したときや、ウィンドウサイズを変更したときにも対応するなら
resizeイベントでふたたびサイズ調整を実行するよう設定します。

var $page = document.getElementById('page');
window.addEventListener('resize', setMinHeight, false);
setMinHeight() {
  if ($page.clientHeight != window.innerHeight)
    $page.style.setProperty('min-height', window.innerHeight + 'px');
};

そのほか、ヘッダとフッタの色が同じならば
bodyの背景色も同じ色にそろえ、$pageの背景色を本文の背景色に設定すると
ページの最初(最後)までスクロールしたときのバウンスでbodyとヘッダ、フッタとの境界がとけて自然になります。

サンプルでは、ヘッダ、フッタ、bodyをグレーに、本文背景を白にしています。
Footer on bottom of page サンプル

関連記事