CSS Grid & Flexbox: Div Fill Remaining Height After Header
Make a div fill remaining screen height after variable header using CSS Grid (auto 1fr) or Flexbox (flex:1). Ditch tables for modern layout. Nested % heights work, full examples & pitfalls explained.
How can I make a div fill the remaining height of the screen after a header using CSS instead of tables?
I’m working on a web application where I want the content area to fill the entire screen height. The page has a header with a logo and account information, which can be of arbitrary height. I need the content div to fill the remaining space to the bottom of the screen.
Currently, I’m using a table-based layout:
CSS:
#page {
height: 100%;
width: 100%
}
#tdcontent {
height: 100%;
}
#content {
overflow: auto; /* or overflow: hidden; */
}
HTML:
<table id="page">
<tr>
<td id="tdheader">
<div id="header">...</div>
</td>
</tr>
<tr>
<td id="tdcontent">
<div id="content">...</div>
</td>
</tr>
</table>
This approach fills the entire page height without scrolling. However, I want to avoid using tables for layout.
Additional requirements:
- Elements inside the content div need to support percentage heights
- For example, if the header takes up 20% of screen height, a table at 50% inside #content should take up 40% of screen space
- The solution should allow nested elements to properly calculate their heights relative to the content area
What CSS techniques can achieve this layout without using tables?
Use CSS Flexbox or CSS Grid to make your content div fill the remaining height after an arbitrary header so nested percentage heights resolve correctly. Set html and body (or a fixed-height wrapper) to a definite height, make the page a column flex container with the header auto-sized and the content set to flex: 1 (and min-height: 0), or use grid-template-rows: auto 1fr for a grid container—both give the content a definite used height so a child with height: 50% becomes 50% of the content area.
Contents
- Quick summary (one-line solutions)
- Why percent heights need a definite parent
- Flexbox solution (flex: 1)
- CSS Grid solution (grid-template-rows: auto 1fr)
- Nested percentage heights and common gotchas
- Browser caveats, 100vh and alternatives
- Complete examples + FAQ
- Sources
- Conclusion
Quick summary (one-line solutions)
Short recipes you can drop into your layout:
- Flexbox: set
html, body(or a wrapper) toheight: 100%, make the page a column flex container and give the contentflex: 1; overflow: auto; min-height: 0;. That makes the content fill the remaining height and lets percent heights inside resolve. - Grid: set the container height (e.g.
height: 100%or100vh) and usegrid-template-rows: auto 1fr;so the header sizes to its content and the main row stretches.
Both patterns are standard solutions (examples and discussion: https://stackoverflow.com/questions/90178/make-a-div-fill-the-height-of-the-remaining-screen-space, https://www.w3docs.com/snippets/html/how-to-make-a-div-fill-the-height-of-the-remaining-space.html).
Why percent heights need a definite parent
Percent heights only work if the element’s containing block has a definite height. If a parent’s height is auto the browser can’t compute “50%” and the percentage collapses to auto. So the trick is to give some ancestor a definite height (for example html, body { height: 100% }, or a wrapper set to height: 100vh) and then let flex/grid compute the content area’s used height.
Example mental model: if the header ends up 20% of the viewport, the content becomes 80% of the viewport; a table inside the content at height: 50% will be 0.5 × 80% = 40% of the viewport. The layout systems below make that math automatic (see also the grid/viewport notes in https://stackoverflow.com/questions/43747185/force-css-grid-container-to-fill-full-screen-of-device).
Flexbox solution (flex: 1)
Why use it: simple, widely supported, and perfect for a header + content column.
Core steps
- Make
htmlandbody(or a root wrapper) have a definite height. - Make the page a column flex container.
- Let header be auto-sized; set content to
flex: 1so it grows to fill remaining space. - Add
min-height: 0andoverflow: autoon the content so inner scrolling works correctly.
Minimal example
<!-- HTML -->
<div id="page">
<header id="header">...logo and account (arbitrary height)...</header>
<main id="content">
<!-- nested elements can use percentage heights -->
<div class="half">This is 50% of the content area</div>
</main>
</div>
/* CSS */
html, body { height: 100%; margin: 0; }
#page {
display: flex;
flex-direction: column;
height: 100%; /* definite height for the flex layout */
}
#header { /* auto height by default */ }
#content {
flex: 1 1 auto; /* fill remaining vertical space */
min-height: 0; /* important: prevents children from forcing overflow */
overflow: auto; /* scroll content internally if needed */
}
.half { height: 50%; } /* resolves to 50% of #content */
Notes and gotchas
min-height: 0on the flex child is often required so a tall child can scroll inside the content instead of expanding the whole page (see explanation and examples: https://stackoverflow.com/questions/15381172/how-can-i-make-flexbox-children-100-height-of-their-parent).- You can nest more flex containers inside
#contentif you prefer usingflexinstead of percentage heights for inner layout. Both approaches work because#contenthas a definite used height.
CSS Grid solution (grid-template-rows: auto 1fr)
Why use it: explicit row tracks make the header/main split very readable. Grid is excellent if you later add a footer or a sidebar.
Core pattern
html, body { height: 100%; margin: 0; }
#page {
display: grid;
grid-template-rows: auto 1fr; /* header auto, content stretches */
height: 100%;
}
#header { grid-row: 1; }
#content { grid-row: 2; overflow: auto; }
Because the grid container has a definite height, the 1fr row has a definite computed size and percentage heights inside #content will resolve relative to it. See a practical write-up: https://www.codegenes.net/blog/make-a-div-fill-the-height-of-the-remaining-screen-space/ and the Grid guide on CSS‑Tricks: https://css-tricks.com/snippets/css/complete-guide-grid/.
If you prefer Tailwind-style examples, the same idea appears in the Tailwind discussion on grid + auto 1fr: https://github.com/tailwindlabs/tailwindcss/discussions/11796.
Nested percentage heights and common gotchas
Common reasons percentage heights fail
- Ancestor(s) do not have a definite height (
auto), so percentages can’t be calculated. - Missing
min-height: 0on flex children. This causes children that are taller than the available space to push the parent rather than scroll. - Using
height: 100vhwithout accounting for mobile browser UI (address bar) — leads to surprising vertical overflow on phones.
How to make nested percentages work reliably
- Ensure the chain from the element up to the root has a definite height. The flex/grid approaches give that to
#content. - If you have several nested levels and want percentage heights at deeper levels, either:
- Give each intermediate parent an explicit height (e.g.,
height: 100%), or - Use flex on the intermediate parent (e.g.,
display:flex; flex-direction:column;) so its children can useflex:1instead of percent heights.
Example: a table inside #content at height: 50% will work if #content is the flex item with flex:1. No JS required.
Browser caveats, 100vh and alternatives
100vh problems
100vhmeasures the viewport but mobile browsers hide/show the address bar; that can make100vhtaller than the visible area and cause overflow. See the grid/viewport discussion in https://stackoverflow.com/questions/43747185/force-css-grid-container-to-fill-full-screen-of-device.
Workarounds
- Preferred: use
html, body { height: 100% }with flex/grid so the browser computes heights without relying onvh. - If you must use viewport units, consider the JS fix that sets a CSS variable to the actual inner height:
// JS: set --vh to 1% of the viewport height
const setVh = () => {
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`);
};
setVh();
window.addEventListener('resize', setVh);
Then in CSS:
/* use calc(var(--vh) * 100) instead of 100vh */
.root { height: calc(var(--vh, 1vh) * 100); }
- Absolute positioning (position: absolute; top:
; bottom: 0) can work, but calculating topfor a variable-height header typically requires JS (or a CSS variable you update with JS). Flexbox/Grid is usually easier and more robust.
Complete examples + FAQ
Full Flexbox example (copy/paste)
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
html,body { height:100%; margin:0; }
#page { display:flex; flex-direction:column; height:100%; }
header { background:#f4f4f4; padding:1rem; }
#content { flex:1 1 auto; min-height:0; overflow:auto; padding:1rem; }
/* nested percentage example */
.half { height:50%; background:#e9e9e9; margin-bottom:8px; }
.half table { width:100%; height:100%; border-collapse:collapse; }
.half td { border:1px solid #ccc; padding:8px; }
</style>
</head>
<body>
<div id="page">
<header>
<h1>Logo + account (arbitrary height)</h1>
<p>Header can wrap or grow.</p>
</header>
<main id="content">
<div class="half">
<table><tr><td>Table at 50% of content</td></tr></table>
</div>
<div style="height:50%; background:#ddd;">Other half</div>
</main>
</div>
</body>
</html>
FAQ (short)
- Why doesn’t
height:100%on a child work? Because one of the parents has no definite height. Make surehtml/bodyor a wrapper hasheight:100%, or use flex/grid so that a parent gets a definite used height. - How do I keep only the content area scrollable? Give
#contentoverflow:autoand the page container a fixed/definite height; avoid letting the header be inside the scrollable region. - Should I choose Grid or Flexbox? Use Flexbox for a simple header + content column. Use Grid if you need explicit row/column tracks or a more complex layout. Both support nested percentage heights when the container has definite height (see examples above and additional write-ups: https://css-tricks.com/snippets/css/complete-guide-grid/, https://www.tutorialrepublic.com/faq/how-to-make-a-div-to-fill-the-height-of-the-remaining-screen-space.php).
Sources
- Stack Overflow — Make a div fill the height of the remaining screen space
- W3Docs — How to Make a Fill the Height of the Remaining Space
- Codegenes — Make a Div Fill Remaining Screen Height After an Arbitrary Header Using CSS
- Tutorial Republic — How to Make a DIV to Fill the Height of the Remaining Screen Space
- Stack Overflow — How can I make Flexbox children 100% height of their parent?
- Stack Overflow — Force CSS Grid container to fill full screen of device
- CSS-Tricks — Complete Guide to CSS Grid
- Tailwind Labs discussion — Grid layout, full height content
- Verpex — Modern Layouts using CSS Grid
Conclusion
Use CSS Grid or Flexbox rather than tables: set
html, body(or a wrapper) to a definite height, then either make a column flex container and give the contentflex: 1(withmin-height: 0; overflow: auto) or usegrid-template-rows: auto 1fr. Both approaches let nested percentage heights resolve correctly so a table atheight: 50%inside the content becomes the expected fraction of the screen.