コンテンツが少ないページでフッターが画面の途中に浮いてしまう、という問題をCSSで解決する方法をまとめました。
結論から書くと、「フッターを最下部に固定する」には2つの意味があり、必要なCSSがまったく違います。コンテンツが短くてもフッターを画面の下端に置きたいならflexかgrid、スクロールしても常にフッターを表示し続けたいならposition: fixedです。
この2つは混同されやすく、前者を「スティッキーフッター」、後者を「固定フッター」と呼び分けます。この記事では両方の書き方と、position: absoluteやposition: stickyを使う場合の注意点までを書きます。
スポンサーリンク
「フッターを最下部に固定」には2つの意味がある
結論:やりたいことが「浮きを直す」のか「常に見せる」のかで、選ぶCSSが変わります。
| 呼び方 | やりたいこと | 使うCSS |
|---|---|---|
| スティッキーフッター | コンテンツが短いときもフッターを画面下端に置く。長いときは文書の末尾に置く | flex または grid |
| 固定フッター | スクロールしても常に画面下端に表示し続ける | position: fixed |
問い合わせ完了ページのように中身が数行しかないページでフッターが中途半端な高さに来る、という症状はスティッキーフッターで直します。一方、カートの合計金額バーのように常時表示したい場合は固定フッターです。
コンテンツが短くてもフッターを画面下端に置く方法(Flexbox)
結論:bodyを縦方向のFlexboxにして最低の高さを画面いっぱいにし、フッターより上の要素にflex: 1を与えます。
<body>
<div class="wrapper">
<!-- ここにコンテンツを配置 -->
</div>
<footer>フッターのコンテンツ</footer>
</body>
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.wrapper {
flex: 1;
}
flex: 1を指定した.wrapperが余った高さをすべて吸収するので、コンテンツが短いときはwrapperが伸びてフッターが下端に押し出されます。コンテンツが長いときはwrapperがそのまま伸び、フッターは文書の末尾に来ます。
min-height: 100vhをheight: 100vhにしないでください。heightにすると高さが固定され、コンテンツが長いときにはみ出します。
この方法が第一候補です。フッターの高さを知る必要がなく、高さが変わっても壊れません。
スポンサーリンク
同じことをCSS Gridで書く
結論:bodyをGridにしてgrid-template-rows: 1fr autoを指定すると、Flexboxと同じ結果になります。
body {
display: grid;
grid-template-rows: 1fr auto;
min-height: 100vh;
margin: 0;
}
1frがコンテンツ領域、autoがフッターです。autoはフッター自身の高さぶんだけ確保し、残りを1frが受け取ります。
Flexboxと違って子要素側にCSSを書く必要がありません。ヘッダーも含めるならgrid-template-rows: auto 1fr autoにします。
CSS Gridの書き方をもう少し詳しく知りたい場合は、CSS Gridの2024年アップデート内容と活用法にまとめています。
スクロールしても常に画面下端に表示する方法(position: fixed)
結論:常時表示したいときはposition: fixedとbottom: 0を指定します。
footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
}
body {
padding-bottom: 60px; /* フッターの高さぶん空ける */
}
position: fixedを指定した要素は通常の配置から外れるため、そのままでは本文の末尾がフッターの下に隠れます。bodyにフッターの高さと同じpadding-bottomを入れて、隠れる領域を確保してください。これを忘れるのがいちばん多い失敗です。
高さぶんの余白を手で合わせるのが面倒な場合は、フッターの高さをCSS変数に持たせておくと管理しやすくなります。
:root {
--footer-height: 60px;
}
footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: var(--footer-height);
}
body {
padding-bottom: var(--footer-height);
}
なお、スマートフォンでは画面の縦幅が狭いので、常時表示のフッターは本文の可読領域をそのぶん削ります。メディアクエリで小さい画面では固定を解除する、という判断もあります。
スポンサーリンク
position: absoluteとposition: stickyはどうなのか
結論:どちらも「フッターを下に置く」目的には使えますが、条件が多く壊れやすいので、FlexboxかGrid、またはposition: fixedを先に検討してください。
position: absoluteは親要素の高さが確定していないと機能しない
結論:position: absolute; bottom: 0;だけでは動きません。基準となる親要素にposition: relativeが必要で、さらにその親の高さが画面いっぱいに確保されている必要があります。
body {
position: relative;
min-height: 100vh;
padding-bottom: 60px; /* フッターの高さぶん */
margin: 0;
box-sizing: border-box;
}
footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
}
ここまで書いてやっとFlexboxの数行と同じ結果になります。フッターの高さを2か所(フッター自身とpadding-bottom)で揃える必要があるため、高さが変わると崩れます。
position: stickyはスティッキーフッターではない
結論:名前は似ていますが、position: stickyで作れるのはスティッキーフッターではありません。
position: sticky; bottom: 0;を指定したフッターは、スクロール中は画面の下端に貼り付き、文書の末尾まで到達すると本来の位置で止まります。「常時表示だが最後は流れに戻る」という挙動で、fixed寄りの動きです。
footer {
position: sticky;
bottom: 0;
}
コンテンツが短いページでフッターが浮く問題は、この指定では直りません。浮きを直したいならFlexboxかGridを使ってください。
スマホで100vhがずれるときは100dvhを使う
結論:iOS Safariの100vhはアドレスバーが隠れた状態の高さで計算されるため、アドレスバーが出ている間はフッターが画面外にはみ出します。100dvhを使うと表示中のバーを含めた実際の高さになります。
body {
display: flex;
flex-direction: column;
min-height: 100vh; /* 古いブラウザ向けのフォールバック */
min-height: 100dvh; /* 対応ブラウザはこちらが適用される */
margin: 0;
}
dvhは動的ビューポート(dynamic viewport)の単位で、Chrome 108・Safari 15.4・Firefox 101以降で使えます。100vhの行を先に書いてから100dvhを書くと、dvhを解釈できないブラウザは後の行を無視してvhのまま表示します。
フッターは<footer>要素で書く
結論:ページ全体のフッターは<div class="footer">ではなく<footer>要素で書きます。
<footer>は、その区画の著作権表示・関連リンク・連絡先などをまとめる要素として定義されています。スクリーンリーダーが領域として認識できるので、支援技術の利用者がページ内を移動しやすくなります。
<article>や<section>の中に置いた<footer>は、そのブロックのフッターという扱いになります。ページ全体のフッターにしたい場合は、<body>の直下に置いてください。
他のセマンティック要素の使い分けは新しいセマンティック要素とその活用法【HTML】にまとめています。