15 CSS Flexbox Layouts 09 / 15
CSS Flexbox Sticky Footer Layout
The definitive flexbox sticky footer pattern — a column flex wrapper with <code>min-height: 100%</code> and <code>flex: 1</code> on the main content pushes the footer to the bottom on any page length.
The code
<div class="fl-09">
<div class="fl-09__page">
<!-- Header -->
<header class="fl-09__header">
<div class="fl-09__logo">
<div class="fl-09__logo-icon">↕</div>
StickyFoot
</div>
<ul class="fl-09__header-nav">
<li class="fl-09__header-link is-active">Home</li>
<li class="fl-09__header-link">Docs</li>
<li class="fl-09__header-link">Examples</li>
<li class="fl-09__header-link">Blog</li>
</ul>
</header>
<!-- Main — flex: 1 gives it all remaining height -->
<main class="fl-09__main">
<!-- Diagram -->
<div class="fl-09__diagram">
<div class="fl-09__zone fl-09__zone--header">
Header <span class="fl-09__zone-code">flex-shrink: 0</span>
</div>
<div class="fl-09__zone fl-09__zone--main">
Main Content <span class="fl-09__zone-code">flex: 1</span>
</div>
<div class="fl-09__zone fl-09__zone--footer">
Footer <span class="fl-09__zone-code">flex-shrink: 0</span>
</div>
</div>
<!-- Explainer -->
<div class="fl-09__explainer">
<div class="fl-09__explainer-header">
<div class="fl-09__explainer-tag">CSS Technique</div>
<div class="fl-09__explainer-title">Sticky Footer with Flexbox</div>
</div>
<div class="fl-09__explainer-body">
<div class="fl-09__code-block">
<span class="fl-09__code-selector">.page</span> {<br>
<span class="fl-09__code-prop"> display</span>: <span class="fl-09__code-val">flex</span>;<br>
<span class="fl-09__code-prop"> flex-direction</span>: <span class="fl-09__code-val">column</span>;<br>
<span class="fl-09__code-prop"> min-height</span>: <span class="fl-09__code-val">100vh</span>;<br>
}<br>
<span class="fl-09__code-selector">.main</span> { <span class="fl-09__code-prop">flex</span>: <span class="fl-09__code-val">1</span>; } <span class="fl-09__code-comment">/* grows */</span><br>
<span class="fl-09__code-selector">.footer</span> { <span class="fl-09__code-prop">flex-shrink</span>: <span class="fl-09__code-val">0</span>; } <span class="fl-09__code-comment">/* fixed */</span>
</div>
<div class="fl-09__explainer-check">
<div class="fl-09__check-icon">✓</div>
Footer sticks to the bottom even when content is short — no JS or absolute positioning needed.
</div>
<div class="fl-09__explainer-check">
<div class="fl-09__check-icon">✓</div>
<code>flex: 1</code> on main is shorthand for <code>flex-grow: 1; flex-shrink: 1; flex-basis: 0</code>, making it absorb all remaining vertical space.
</div>
</div>
</div>
</main>
<!-- Footer — flex-shrink: 0 keeps it pinned -->
<footer class="fl-09__footer">
<div class="fl-09__footer-top">
<div>
<div class="fl-09__footer-brand">StickyFoot</div>
<div class="fl-09__footer-tagline">Pure CSS sticky footer<br>with flexbox column layout.</div>
</div>
<div>
<div class="fl-09__footer-col-title">Product</div>
<ul class="fl-09__footer-links">
<li>Features</li><li>Pricing</li><li>Changelog</li>
</ul>
</div>
<div>
<div class="fl-09__footer-col-title">Company</div>
<ul class="fl-09__footer-links">
<li>About</li><li>Blog</li><li>Careers</li>
</ul>
</div>
</div>
<div class="fl-09__footer-bottom">
<span>© 2025 StickyFoot. MIT License.</span>
<div class="fl-09__footer-socials">
<div class="fl-09__social-btn">𝕏</div>
<div class="fl-09__social-btn">in</div>
<div class="fl-09__social-btn">gh</div>
</div>
</div>
</footer>
</div>
</div> <div class="fl-09">
<div class="fl-09__page">
<!-- Header -->
<header class="fl-09__header">
<div class="fl-09__logo">
<div class="fl-09__logo-icon">↕</div>
StickyFoot
</div>
<ul class="fl-09__header-nav">
<li class="fl-09__header-link is-active">Home</li>
<li class="fl-09__header-link">Docs</li>
<li class="fl-09__header-link">Examples</li>
<li class="fl-09__header-link">Blog</li>
</ul>
</header>
<!-- Main — flex: 1 gives it all remaining height -->
<main class="fl-09__main">
<!-- Diagram -->
<div class="fl-09__diagram">
<div class="fl-09__zone fl-09__zone--header">
Header <span class="fl-09__zone-code">flex-shrink: 0</span>
</div>
<div class="fl-09__zone fl-09__zone--main">
Main Content <span class="fl-09__zone-code">flex: 1</span>
</div>
<div class="fl-09__zone fl-09__zone--footer">
Footer <span class="fl-09__zone-code">flex-shrink: 0</span>
</div>
</div>
<!-- Explainer -->
<div class="fl-09__explainer">
<div class="fl-09__explainer-header">
<div class="fl-09__explainer-tag">CSS Technique</div>
<div class="fl-09__explainer-title">Sticky Footer with Flexbox</div>
</div>
<div class="fl-09__explainer-body">
<div class="fl-09__code-block">
<span class="fl-09__code-selector">.page</span> {<br>
<span class="fl-09__code-prop"> display</span>: <span class="fl-09__code-val">flex</span>;<br>
<span class="fl-09__code-prop"> flex-direction</span>: <span class="fl-09__code-val">column</span>;<br>
<span class="fl-09__code-prop"> min-height</span>: <span class="fl-09__code-val">100vh</span>;<br>
}<br>
<span class="fl-09__code-selector">.main</span> { <span class="fl-09__code-prop">flex</span>: <span class="fl-09__code-val">1</span>; } <span class="fl-09__code-comment">/* grows */</span><br>
<span class="fl-09__code-selector">.footer</span> { <span class="fl-09__code-prop">flex-shrink</span>: <span class="fl-09__code-val">0</span>; } <span class="fl-09__code-comment">/* fixed */</span>
</div>
<div class="fl-09__explainer-check">
<div class="fl-09__check-icon">✓</div>
Footer sticks to the bottom even when content is short — no JS or absolute positioning needed.
</div>
<div class="fl-09__explainer-check">
<div class="fl-09__check-icon">✓</div>
<code>flex: 1</code> on main is shorthand for <code>flex-grow: 1; flex-shrink: 1; flex-basis: 0</code>, making it absorb all remaining vertical space.
</div>
</div>
</div>
</main>
<!-- Footer — flex-shrink: 0 keeps it pinned -->
<footer class="fl-09__footer">
<div class="fl-09__footer-top">
<div>
<div class="fl-09__footer-brand">StickyFoot</div>
<div class="fl-09__footer-tagline">Pure CSS sticky footer<br>with flexbox column layout.</div>
</div>
<div>
<div class="fl-09__footer-col-title">Product</div>
<ul class="fl-09__footer-links">
<li>Features</li><li>Pricing</li><li>Changelog</li>
</ul>
</div>
<div>
<div class="fl-09__footer-col-title">Company</div>
<ul class="fl-09__footer-links">
<li>About</li><li>Blog</li><li>Careers</li>
</ul>
</div>
</div>
<div class="fl-09__footer-bottom">
<span>© 2025 StickyFoot. MIT License.</span>
<div class="fl-09__footer-socials">
<div class="fl-09__social-btn">𝕏</div>
<div class="fl-09__social-btn">in</div>
<div class="fl-09__social-btn">gh</div>
</div>
</div>
</footer>
</div>
</div>.fl-09, .fl-09 *, .fl-09 *::before, .fl-09 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.fl-09 ::selection { background: #0891b2; color: #fff; }
.fl-09 {
--bg: #f0f4f8;
--surface: #fff;
--ink: #0f2139;
--muted: #64748b;
--accent: #0891b2;
--accent2: #0e7490;
--footer-bg: #0f2139;
--border: #dde4ec;
--green: #059669;
font-family: 'Manrope', sans-serif;
background: var(--bg);
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--border);
}
/*
STICKY FOOTER TECHNIQUE:
Outer wrapper = flex column, min-height set.
Main content = flex: 1 (grows to fill space).
Footer = flex-shrink: 0 (never collapses).
This pushes the footer to the bottom even when content is short.
*/
.fl-09__page {
display: flex;
flex-direction: column;
min-height: 500px;
}
/* ── Header ── */
.fl-09__header {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 0 28px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.fl-09__logo {
font-size: 1rem;
font-weight: 800;
color: var(--ink);
display: flex;
align-items: center;
gap: 8px;
}
.fl-09__logo-icon {
width: 28px;
height: 28px;
background: var(--accent);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
color: #fff;
}
.fl-09__header-nav {
display: flex;
gap: 4px;
list-style: none;
}
.fl-09__header-link {
padding: 6px 12px;
border-radius: 6px;
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
cursor: pointer;
transition: all 0.15s;
}
.fl-09__header-link:hover { color: var(--ink); background: var(--bg); }
.fl-09__header-link.is-active { color: var(--accent); }
/* ── Main content (grows with flex: 1) ── */
.fl-09__main {
flex: 1; /* ← this is the sticky footer magic */
padding: 36px 28px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 24px;
}
/* Technique explainer card */
.fl-09__explainer {
max-width: 560px;
width: 100%;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
}
.fl-09__explainer-header {
background: linear-gradient(135deg, #0e4f6e, #0891b2);
padding: 20px 24px;
}
.fl-09__explainer-tag {
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255,255,255,0.6);
margin-bottom: 6px;
}
.fl-09__explainer-title {
font-size: 1.1rem;
font-weight: 800;
color: #fff;
}
.fl-09__explainer-body {
padding: 20px 24px;
display: flex;
flex-direction: column;
gap: 14px;
}
.fl-09__code-block {
background: #0f2139;
border-radius: 8px;
padding: 14px 16px;
font-family: 'Courier New', monospace;
font-size: 0.75rem;
line-height: 1.8;
color: #94a3b8;
}
.fl-09__code-comment { color: #475569; }
.fl-09__code-prop { color: #7dd3fc; }
.fl-09__code-val { color: #86efac; }
.fl-09__code-selector { color: #c084fc; }
.fl-09__explainer-desc {
font-size: 0.8rem;
color: var(--muted);
line-height: 1.7;
}
.fl-09__explainer-check {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.78rem;
color: var(--ink);
font-weight: 500;
}
.fl-09__check-icon {
width: 18px;
height: 18px;
border-radius: 50%;
background: rgba(5,150,105,0.12);
color: var(--green);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.62rem;
font-weight: 800;
flex-shrink: 0;
margin-top: 1px;
}
/* Diagram showing layout zones */
.fl-09__diagram {
max-width: 560px;
width: 100%;
display: flex;
flex-direction: column;
gap: 4px;
}
.fl-09__zone {
border-radius: 8px;
padding: 10px 14px;
font-size: 0.72rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: space-between;
}
.fl-09__zone-code {
font-family: 'Courier New', monospace;
font-size: 0.68rem;
opacity: 0.7;
}
.fl-09__zone--header { background: rgba(8,145,178,0.15); color: var(--accent2); }
.fl-09__zone--main { background: rgba(8,145,178,0.06); color: var(--muted); border: 1px dashed rgba(8,145,178,0.2); flex: 1; min-height: 36px; }
.fl-09__zone--footer { background: rgba(15,33,57,0.08); color: var(--ink); }
/* ── Footer (flex-shrink: 0) ── */
.fl-09__footer {
background: var(--footer-bg);
padding: 24px 28px;
flex-shrink: 0; /* ← never shrinks; stays at bottom */
}
.fl-09__footer-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
margin-bottom: 20px;
}
.fl-09__footer-brand {
font-size: 0.92rem;
font-weight: 800;
color: #fff;
margin-bottom: 6px;
}
.fl-09__footer-tagline {
font-size: 0.72rem;
color: rgba(255,255,255,0.35);
line-height: 1.5;
}
.fl-09__footer-col-title {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255,255,255,0.35);
margin-bottom: 8px;
}
.fl-09__footer-links {
list-style: none;
display: flex;
flex-direction: column;
gap: 6px;
}
.fl-09__footer-links li {
font-size: 0.76rem;
color: rgba(255,255,255,0.5);
cursor: pointer;
transition: color 0.15s;
}
.fl-09__footer-links li:hover { color: #fff; }
.fl-09__footer-bottom {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 16px;
border-top: 1px solid rgba(255,255,255,0.08);
font-size: 0.7rem;
color: rgba(255,255,255,0.3);
}
.fl-09__footer-socials {
display: flex;
gap: 8px;
}
.fl-09__social-btn {
width: 28px;
height: 28px;
border-radius: 6px;
background: rgba(255,255,255,0.06);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
cursor: pointer;
transition: background 0.15s;
}
.fl-09__social-btn:hover { background: rgba(255,255,255,0.12); }
@media (prefers-reduced-motion: reduce) {
.fl-09__header-link, .fl-09__footer-links li,
.fl-09__social-btn { transition: none; }
} .fl-09, .fl-09 *, .fl-09 *::before, .fl-09 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.fl-09 ::selection { background: #0891b2; color: #fff; }
.fl-09 {
--bg: #f0f4f8;
--surface: #fff;
--ink: #0f2139;
--muted: #64748b;
--accent: #0891b2;
--accent2: #0e7490;
--footer-bg: #0f2139;
--border: #dde4ec;
--green: #059669;
font-family: 'Manrope', sans-serif;
background: var(--bg);
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--border);
}
/*
STICKY FOOTER TECHNIQUE:
Outer wrapper = flex column, min-height set.
Main content = flex: 1 (grows to fill space).
Footer = flex-shrink: 0 (never collapses).
This pushes the footer to the bottom even when content is short.
*/
.fl-09__page {
display: flex;
flex-direction: column;
min-height: 500px;
}
/* ── Header ── */
.fl-09__header {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 0 28px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.fl-09__logo {
font-size: 1rem;
font-weight: 800;
color: var(--ink);
display: flex;
align-items: center;
gap: 8px;
}
.fl-09__logo-icon {
width: 28px;
height: 28px;
background: var(--accent);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
color: #fff;
}
.fl-09__header-nav {
display: flex;
gap: 4px;
list-style: none;
}
.fl-09__header-link {
padding: 6px 12px;
border-radius: 6px;
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
cursor: pointer;
transition: all 0.15s;
}
.fl-09__header-link:hover { color: var(--ink); background: var(--bg); }
.fl-09__header-link.is-active { color: var(--accent); }
/* ── Main content (grows with flex: 1) ── */
.fl-09__main {
flex: 1; /* ← this is the sticky footer magic */
padding: 36px 28px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 24px;
}
/* Technique explainer card */
.fl-09__explainer {
max-width: 560px;
width: 100%;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
}
.fl-09__explainer-header {
background: linear-gradient(135deg, #0e4f6e, #0891b2);
padding: 20px 24px;
}
.fl-09__explainer-tag {
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255,255,255,0.6);
margin-bottom: 6px;
}
.fl-09__explainer-title {
font-size: 1.1rem;
font-weight: 800;
color: #fff;
}
.fl-09__explainer-body {
padding: 20px 24px;
display: flex;
flex-direction: column;
gap: 14px;
}
.fl-09__code-block {
background: #0f2139;
border-radius: 8px;
padding: 14px 16px;
font-family: 'Courier New', monospace;
font-size: 0.75rem;
line-height: 1.8;
color: #94a3b8;
}
.fl-09__code-comment { color: #475569; }
.fl-09__code-prop { color: #7dd3fc; }
.fl-09__code-val { color: #86efac; }
.fl-09__code-selector { color: #c084fc; }
.fl-09__explainer-desc {
font-size: 0.8rem;
color: var(--muted);
line-height: 1.7;
}
.fl-09__explainer-check {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.78rem;
color: var(--ink);
font-weight: 500;
}
.fl-09__check-icon {
width: 18px;
height: 18px;
border-radius: 50%;
background: rgba(5,150,105,0.12);
color: var(--green);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.62rem;
font-weight: 800;
flex-shrink: 0;
margin-top: 1px;
}
/* Diagram showing layout zones */
.fl-09__diagram {
max-width: 560px;
width: 100%;
display: flex;
flex-direction: column;
gap: 4px;
}
.fl-09__zone {
border-radius: 8px;
padding: 10px 14px;
font-size: 0.72rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: space-between;
}
.fl-09__zone-code {
font-family: 'Courier New', monospace;
font-size: 0.68rem;
opacity: 0.7;
}
.fl-09__zone--header { background: rgba(8,145,178,0.15); color: var(--accent2); }
.fl-09__zone--main { background: rgba(8,145,178,0.06); color: var(--muted); border: 1px dashed rgba(8,145,178,0.2); flex: 1; min-height: 36px; }
.fl-09__zone--footer { background: rgba(15,33,57,0.08); color: var(--ink); }
/* ── Footer (flex-shrink: 0) ── */
.fl-09__footer {
background: var(--footer-bg);
padding: 24px 28px;
flex-shrink: 0; /* ← never shrinks; stays at bottom */
}
.fl-09__footer-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
margin-bottom: 20px;
}
.fl-09__footer-brand {
font-size: 0.92rem;
font-weight: 800;
color: #fff;
margin-bottom: 6px;
}
.fl-09__footer-tagline {
font-size: 0.72rem;
color: rgba(255,255,255,0.35);
line-height: 1.5;
}
.fl-09__footer-col-title {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: rgba(255,255,255,0.35);
margin-bottom: 8px;
}
.fl-09__footer-links {
list-style: none;
display: flex;
flex-direction: column;
gap: 6px;
}
.fl-09__footer-links li {
font-size: 0.76rem;
color: rgba(255,255,255,0.5);
cursor: pointer;
transition: color 0.15s;
}
.fl-09__footer-links li:hover { color: #fff; }
.fl-09__footer-bottom {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 16px;
border-top: 1px solid rgba(255,255,255,0.08);
font-size: 0.7rem;
color: rgba(255,255,255,0.3);
}
.fl-09__footer-socials {
display: flex;
gap: 8px;
}
.fl-09__social-btn {
width: 28px;
height: 28px;
border-radius: 6px;
background: rgba(255,255,255,0.06);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
cursor: pointer;
transition: background 0.15s;
}
.fl-09__social-btn:hover { background: rgba(255,255,255,0.12); }
@media (prefers-reduced-motion: reduce) {
.fl-09__header-link, .fl-09__footer-links li,
.fl-09__social-btn { transition: none; }
}How this works
The outer wrapper uses display: flex; flex-direction: column; min-height: 500px. The header and footer both carry flex-shrink: 0 so they never compress, while the main content area has flex: 1 — meaning it grows to fill all remaining vertical space. When content is short, the main section expands invisibly to push the footer down. When content is long, it grows naturally and the footer follows.
This is the modern replacement for the negative-margin and calc-based sticky footer hacks. No fixed heights are needed anywhere — only the wrapper needs a minimum height and the main section needs flex: 1.
Customize
- Change the minimum page height by editing
min-heighton.fl-09__wrapper— use100vhfor a full-viewport page shell. - Add a second sticky bar (e.g. a cookie banner) by prepending it before the header with
flex-shrink: 0; the main still fills leftover space. - Give the footer a multi-column layout by making it a nested row flex container with
justify-content: space-betweeninside the sticky shell. - Center main content vertically when it's short by adding
justify-content: centerto.fl-09__main(which itself is a column flex container). - Add a floating action button that stays above the footer by using
position: sticky; bottom: 16pxinside the main flex child.
Watch out for
- The sticky footer only works if the
htmlandbodyelements also haveheight: 100%— inside a scoped demo wrapper, the wrapper min-height substitutes for this. flex: 1is shorthand forflex-grow: 1; flex-shrink: 1; flex-basis: 0— the zero basis means it starts from nothing and grows, which is correct here.- Using
height: 100vhinstead ofmin-heightcaps the wrapper — content taller than the viewport clips; always prefermin-height.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 29+ | 9+ | 28+ | 29+ |
Universally supported baseline flexbox pattern; works in IE 11 with -ms-flex prefixes and explicit heights on html, body.