Question
I am building a web application where the main content area should fill the remaining height of the viewport.
The page has two main sections:
- a
headerarea containing a logo and account information - a
contentarea that should stretch from below the header to the bottom of the screen
The header can have an arbitrary height, so I cannot hard-code its size.
Right now I am using a table-based layout:
<table id="page">
<tr>
<td id="tdheader">
<div id="header">...</div>
</td>
</tr>
<tr>
<td id="tdcontent">
<div id="content">...</div>
</td>
</tr>
</table>
#page {
height: 100%;
width: 100%;
}
#tdcontent {
height: 100%;
}
#content {
overflow: auto; /* or overflow: hidden; */
}
This fills the full page height without requiring the whole page to scroll.
Also, elements inside the content area may use percentage heights. For example:
- an element with
height: 100%should fill the content area - two elements with
height: 50%should each take half of the content area
If the header takes 20% of the screen height, then a table with height: 50% inside #content should take 40% of the screen height.
Is there a way to achieve this same effect without using a table for layout?
Short Answer
By the end of this page, you will understand how to make a section fill the remaining viewport height below a header with unknown height. You will learn why percentage heights often fail, how modern CSS layout tools like Flexbox solve this cleanly, and how to structure nested elements so height: 100% and other percentage-based heights work reliably.
Concept
In CSS, making one element fill the remaining height is a layout problem. The browser needs to know two things:
- the total available height
- how much space other elements already use
Traditional table layouts could do this automatically, which is why they were often used in older web apps. But modern CSS provides better tools for this, especially Flexbox.
The key idea is:
- make the page take up the full viewport height
- let the header size itself naturally
- allow the content area to grow and fill whatever space is left
This is exactly what Flexbox is designed for.
A very common beginner issue is trying to solve this with height: 100% alone. That often does not work unless every parent element has a defined height. Percentage heights depend on the height of the parent, so if the parent's height is auto, the child's percentage height cannot be resolved the way you expect.
For layouts like:
- header
- main content fills the rest
- nested panels inside content use percentage heights
Flexbox is usually the best solution.
Why this matters in real programming:
- dashboard layouts often need a fixed or variable header with a scrollable body
- admin apps commonly need side panels or content regions that fill available space
- modals, editors, and split-view UIs often depend on parent-controlled height
- data tables and charts frequently need to stretch inside a container
So this is not just about one div; it is about understanding how height flows through a layout.
Mental Model
Think of the page like a vertical stack of boxes inside a bookshelf with a fixed height.
- The bookshelf is the viewport.
- The header is a box that takes however much room it needs.
- The content area is a flexible box that expands to fill all remaining shelf space.
Inside that flexible content box, you can then divide the space again:
- one child can take
100% - two children can take
50%each
But this only works if the parent box has a real, known height.
So the rule of thumb is:
percentage heights work only when the parent has a definite height.
Flexbox helps create that definite remaining height automatically.
Syntax and Examples
Basic Flexbox solution
<div class="page">
<header class="header">
Logo and account info
</header>
<main class="content">
Main content
</main>
</div>
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
padding: 16px;
background: #ddd;
}
.content {
flex: 1;
overflow: auto;
background: #f5f5f5;
}
What this does
height: 100vhmakes.pageas tall as the viewportdisplay: flexwithflex-direction: columnstacks children vertically.headerkeeps its natural height.content { flex: 1; }fills the remaining space
Example with percentage-height children inside content
<div class="page">
<header class="header">Header</header>
<main class="content">
<div class="top-half">Top half</div>
<div class="bottom-half">Bottom half</div>
</main>
</div>
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
padding: 20px;
background: #ccc;
}
.content {
flex: 1;
background: #eee;
}
.top-half,
.bottom-half {
height: 50%;
}
.top-half {
background: lightblue;
}
.bottom-half {
background: lightgreen;
}
Because .content gets an actual height from the flex layout, its children can use percentage heights.
Common improvement: allow scrolling only in content
.content {
flex: 1;
overflow: auto;
min-height: 0;
}
min-height: 0 is often important in Flexbox layouts when the content should shrink and scroll instead of overflowing.
Step by Step Execution
Consider this example:
<div class="page">
<header class="header">My Header</header>
<main class="content">
<div class="box">I fill the remaining height</div>
</main>
</div>
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
padding: 24px;
}
.content {
flex: 1;
}
.box {
height: 100%;
background: peachpuff;
}
Step by step
htmlandbodyare given full height..pageis set to100vh, so it becomes exactly as tall as the viewport..pageusesdisplay: flexandflex-direction: column, so its children are stacked vertically..headertakes up only the height it needs based on its content and padding..contenthasflex: 1, so it grows to fill all the leftover vertical space..boxhasheight: 100%, so it becomes as tall as.content.
If the header grows taller, .content automatically becomes shorter. No manual height calculation is needed.
Example trace
Suppose the viewport is 800px tall.
- header height becomes
120px - remaining space is
680px .contentbecomes680pxtall.boxwithheight: 100%also becomes680pxtall
If you had two children inside .content with height: 50%, each would become 340px tall.
Real World Use Cases
Where this pattern is used
Dashboards
A dashboard may have:
- a top navigation bar
- a chart or data table below it
The chart area should fill the remaining height and scroll internally if needed.
Admin panels
Many admin tools use:
- a header with account actions
- a main working area below
This keeps the top controls visible while the main content grows and scrolls.
Chat applications
A chat app often has:
- a header with room or user info
- a message list filling the remaining space
- sometimes nested panels inside the content area
Code editors and IDE-like layouts
Browser-based editors often need:
- a toolbar at the top
- editor panels filling the rest of the screen
Data tables
A page may need a filter bar on top and a table below that fills the rest of the viewport without making the entire page scroll.
Real Codebase Usage
In real projects, developers usually combine this pattern with a few common layout habits.
1. Flex column shell
A common app shell looks like this:
.app {
height: 100vh;
display: flex;
flex-direction: column;
}
.app-main {
flex: 1;
min-height: 0;
}
This creates a reliable full-height page structure.
2. Scroll only where needed
Instead of scrolling the whole page, developers often scroll just the content region:
.app-main {
flex: 1;
overflow: auto;
min-height: 0;
}
This is useful for sticky headers, fixed toolbars, and split layouts.
3. Nested flex layouts
Inside the content area, developers often create another flex layout:
.content {
display: flex;
flex-direction: column;
}
.panel {
flex: 1;
}
This is common for forms, tables, sidebars, and multi-panel screens.
4. Guarding percentage heights
If a child uses height: 100%, developers make sure every relevant parent has a defined height or is sized by flex/grid. Otherwise the percentage height may collapse or behave unexpectedly.
5. Avoiding table layout for page structure
Real codebases generally avoid tables for layout because:
- they are meant for tabular data
- they are less flexible than modern layout systems
- they can make responsive design harder
- they mix document meaning with visual layout
Common Mistakes
1. Using height: 100% without defining parent height
Broken example:
.content {
height: 100%;
}
This does not work if the parent does not have a definite height.
Fix
Make the parent a full-height container or use Flexbox:
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
2. Forgetting to set html, body height
If you rely on percentage heights, this matters.
Broken example:
body {
margin: 0;
}
.page {
height: 100%;
}
Fix
html, body {
height: 100%;
margin: 0;
}
3. Expecting percentage child heights to work inside an auto-height parent
Broken example:
.content {
background: #eee;
}
.child {
height: 50%;
}
If .content has no defined height, .child cannot reliably use 50%.
Fix
Give .content a real height through flex sizing.
4. Forgetting min-height: 0 in flex layouts
A flex child may refuse to shrink and overflow instead of scrolling.
Fix
.content {
flex: 1;
min-height: 0;
overflow: auto;
}
5. Using tables for non-tabular layout
Tables can appear to solve the height problem, but they are the wrong tool for general page layout.
Use tables for data, not for structuring the whole page.
6. Hard-coding header height unnecessarily
Broken approach:
.content {
height: calc(100vh - 80px);
}
This only works if the header is always 80px tall.
Better approach
Let the header size naturally and let Flexbox fill the rest.
Comparisons
| Approach | Best for | Handles unknown header height | Supports remaining space well | Notes |
|---|---|---|---|---|
table layout | Old layouts | Yes | Yes | Works, but not recommended for page layout |
height: 100% only | Simple cases | No | Weak | Requires defined heights on all parents |
calc(100vh - 80px) | Fixed-height header | No | Good | Breaks if header height changes |
| Flexbox | Modern app layouts | Yes | Excellent | Best fit for header + remaining content |
| CSS Grid | More complex 2D layouts | Yes | Excellent | Great when rows and columns are both important |
Flexbox vs calc()
.content {
height: calc(100vh - 80px);
}
This is fine only when the header height is known and fixed.
.page {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
flex: 1;
}
This works when the header height is dynamic.
Flexbox vs CSS Grid
Both can solve this.
Flexbox
Better when the layout is mainly one-dimensional: a vertical stack of header and content.
Grid
Useful if you also need columns or more complex row/column control.
Example grid version:
.page {
display: grid;
grid-template-rows: auto 1fr;
height: 100vh;
}
This means:
- first row: natural header height
- second row: all remaining space
Cheat Sheet
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
/* natural height */
}
.content {
flex: 1;
min-height: 0;
overflow: auto;
}
Rules to remember
height: 100%needs a parent with a defined height.flex: 1makes an element fill remaining space.- Use
min-height: 0on flex children that should shrink and scroll. - Use tables for tabular data, not page layout.
- Use
100vhwhen you want viewport height. - If child elements use percentage heights, the parent must have a real computed height.
Useful alternatives
Flexbox
.page {
display: flex;
flex-direction: column;
height: 100vh;
}
Grid
.page {
display: grid;
grid-template-rows: auto 1fr;
height: 100vh;
}
Fixed header only
.content {
height: calc(100vh - 80px);
}
Use this only if the header height is known.
Common debugging checks
- Did you set
html, body { height: 100%; }if using%heights? - Does the parent actually have a defined height?
- Is a flex child missing
min-height: 0? - Are you trying to use
%height inside an auto-sized container?
FAQ
How do I make a div take the rest of the page height?
Use a parent container with display: flex, flex-direction: column, and give the content area flex: 1.
Why does height: 100% not work in my div?
Because percentage height only works when the parent has a defined height. If the parent height is auto, the child cannot reliably fill it.
Can I do this without knowing the header height?
Yes. Flexbox and Grid both work well when the header has dynamic height.
Is using a table for page layout bad?
It is outdated for general layout. Tables are intended for tabular data, not app page structure.
What if I want only the content area to scroll?
Set overflow: auto on the content area and keep the overall page container at viewport height.
Can children inside the content area use height: 50% or height: 100%?
Yes, as long as the content area has a definite height, which Flexbox can provide.
Should I use Flexbox or Grid for this layout?
Use Flexbox for a simple vertical header/content layout. Use Grid if the page also needs more complex rows and columns.
Mini Project
Description
Build a simple app-style page with a variable-height header and a content area that fills the rest of the screen. Inside the content area, split the space into two equal sections using percentage heights. This demonstrates how to create a full-height layout without table-based markup.
Goal
Create a responsive page where the header keeps its natural height and the content area fills the remaining viewport height.
Requirements
- Create a page container that fills the viewport height.
- Add a header with natural, content-based height.
- Make the main content area fill the remaining vertical space.
- Inside the content area, add two panels that each take 50% of the content height.
- Make the content area scroll if its content becomes too large.
Keep learning
Related questions
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.
CSS ::before and ::after on Input Elements
Learn why CSS ::before and ::after usually do not work on input elements, what replaced elements are, and practical alternatives.