CSS Sticky Footer with Flexbox — Keep Footer at Bottom of Page
A sticky footer stays at the bottom of the viewport when content is short, and below the content when content is tall. The flexbox approach is the cleanest modern solution...
A sticky footer stays at the bottom of the viewport when content is short, and scrolls naturally below the content when content is long. Flexbox makes this effortless.
Build flexbox layouts with the Flexbox Generator.
The flexbox sticky footer pattern
/* HTML structure:
<body>
<header>...</header>
<main>...</main>
<footer>...</footer>
</body>
*/
body {
display: flex;
flex-direction: column;
min-height: 100vh; /* At least full viewport height */
margin: 0;
}
main {
flex: 1; /* Grow to fill available space */
/* This pushes the footer to the bottom */
}
footer {
/* No special styling needed — footer stays at bottom automatically */
}
That’s it. When content is short, main { flex: 1 } expands to fill the space between header and footer. When content is tall, min-height: 100vh allows the page to grow naturally.
With multiple sections
body {
display: flex;
flex-direction: column;
min-height: 100dvh; /* dvh = dynamic viewport height (mobile-safe) */
}
header { flex-shrink: 0; }
nav { flex-shrink: 0; }
main {
flex: 1; /* Pushes everything below it to the bottom */
}
.pre-footer { flex-shrink: 0; }
footer { flex-shrink: 0; }
Using 100dvh instead of 100vh
On mobile browsers, 100vh can include or exclude the browser’s dynamic toolbar (address bar), causing layout jumps. Use 100dvh for modern mobile-safe behavior:
body {
min-height: 100dvh; /* dvh = dynamic viewport height */
/* 100dvh = visible viewport height, excludes mobile browser chrome */
}
/* Fallback for older browsers: */
body {
min-height: 100vh;
min-height: 100dvh; /* Overrides if supported */
}
App shell layout (header + scrollable main + footer)
/* For an app with a fixed header, scrollable content, fixed footer */
.app-shell {
display: flex;
flex-direction: column;
height: 100dvh; /* Exact viewport height */
overflow: hidden;
}
.app-header {
flex-shrink: 0;
height: 64px;
}
.app-main {
flex: 1;
overflow-y: auto; /* Scroll only the main area */
overflow-x: hidden;
}
.app-footer {
flex-shrink: 0;
height: 56px;
}
React layout component
function PageLayout({ children }) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
minHeight: '100dvh',
}}
>
<Header />
<main style={{ flex: 1 }}>
{children}
</main>
<Footer />
</div>
);
}
With Tailwind CSS
<body class="flex flex-col min-h-screen">
<header class="shrink-0">...</header>
<main class="flex-1">...</main>
<footer class="shrink-0">...</footer>
</body>
Sticky footer for individual sections
/* A card with a footer button always at the bottom */
.card {
display: flex;
flex-direction: column;
height: 400px; /* Fixed height card */
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 1.5rem;
}
.card-content {
flex: 1; /* Takes all available space */
overflow-y: auto; /* Scroll if content is long */
}
.card-footer {
padding-top: 1rem;
border-top: 1px solid #e2e8f0;
/* Always at bottom of card */
}
Comparison: old fixed vs flexbox approach
/* ❌ Old approach: margin trick */
.content { margin-bottom: 80px; } /* Equal to footer height */
footer {
position: fixed;
bottom: 0;
width: 100%;
height: 80px;
}
/* Problems: fixed footer covers content, scroll behavior issues */
/* ❌ Old approach: table layout */
html, body { height: 100%; }
.wrapper { display: table; height: 100%; width: 100%; }
.main { display: table-row; height: 100%; }
footer { display: table-row; }
/* Works but semantically wrong and fragile */
/* ✅ Modern: flexbox */
body { display: flex; flex-direction: column; min-height: 100dvh; }
main { flex: 1; }
Related tools
- Flexbox Generator — visualize flexbox layouts
- CSS Grid Generator — grid-based page layouts
- PX to REM Converter — convert layout units
Related posts
- CSS Flexbox Cheatsheet — Every Property with Visual Examples — CSS Flexbox has 12 container properties and 6 item properties. Here's a complete…
- CSS flex-order Property — Reorder Flex Items Without Changing HTML — The CSS order property reorders flex items visually without changing the DOM. Le…
- CSS Flexbox — Complete Guide to flex-direction, justify-content, and align-items — Flexbox aligns items in one dimension — a row or a column. Here's how flex-direc…
- CSS flex-grow, flex-shrink, flex-basis — The Flex Property Explained — The CSS flex shorthand controls three properties: flex-grow (how much to expand)…
- Flexbox Alignment — justify-content, align-items, and align-self — Master Flexbox alignment properties: justify-content distributes items along the…
Related tool
Visual CSS Flexbox playground. Live preview + copyable CSS. Control direction, wrap, justify, align, gap. Example child layouts.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.