Question
I am building a web application where the main content area should fill the remaining height of the viewport.
The page contains:
- a
headerarea with a logo and account information - a
contentarea that should stretch from the bottom of 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 like this:
<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 makes the page fill the full height, and scrolling is not required for the overall page.
I want to achieve the same effect without using a table for layout.
There is one additional requirement: elements inside the content div may also use percentage heights. For example:
- one child at
height: 100%should fill the content area - two children at
height: 50%should split the content area evenly
For example, if the header takes up 20% of the screen height, then a table inside #content with height: 50% should end up using 40% of the viewport height.
Is there a CSS-based way to do this with normal div elements instead of a table layout?
Short Answer
By the end of this page, you will understand how to make a layout where a header keeps its natural height and the content area fills the remaining viewport height. You will also learn how to make percentage heights work correctly inside that content area using modern CSS, especially Flexbox.
Concept
The core concept here is creating a parent container with a known height, then letting one child grow to fill the remaining space.
In CSS, percentage heights only work when the browser can determine the height of the parent. That is why table layouts often seemed to solve this problem in older code: table cells naturally participate in height calculations.
With normal div elements, the modern solution is usually Flexbox.
The typical idea is:
- Make the page container as tall as the viewport.
- Let the header take its natural height.
- Let the content area grow to fill the rest.
- Give the content area a definite computed height so percentage-based children can size themselves correctly.
A common pattern looks like this:
bodyor a wrapper getsmin-height: 100vhorheight: 100vh- wrapper gets
display: flex - wrapper uses
flex-direction: column - header stays natural size
- content gets
flex: 1
Why this matters in real programming:
- app layouts often have a top bar and a main content panel
- dashboards need panels that fill the remaining screen area
- scrollable content regions are common in admin tools and web apps
- embedded tables, sidebars, editors, and split panes often depend on percentage heights
The most important rule to remember is:
Mental Model
Think of the page like a vertical stack inside a fixed-height container.
- The viewport is the full container.
- The header is a box that takes however much space it needs.
- The content area is a flexible box that expands to occupy everything left over.
Imagine packing a suitcase:
- first, put in the header item
- then the remaining space automatically belongs to the content item
If the suitcase itself has a known height, then anything inside the content area can also measure itself as a percentage of that remaining space.
So the key mental model is:
known outer height -> flexible remaining area -> percentage-sized inner children
Syntax and Examples
Basic Flexbox layout
<div class="page">
<header class="header">
<h1>Logo</h1>
<p>Account info</p>
</header>
<main class="content">
<div class="panel">Main content</div>
</main>
</div>
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
padding: 16px;
: ;
}
{
: ;
: auto;
: ;
}
{
: ;
: ;
}
Step by Step Execution
Consider this example:
<div class="page">
<header class="header">My Header</header>
<main class="content">
<div class="inner">I fill the remaining height</div>
</main>
</div>
html, body {
height: 100%;
margin: 0;
}
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
padding: 30px;
}
.content {
flex: 1;
}
.inner {
height: 100%;
}
Step by step
Real World Use Cases
This layout pattern appears in many real applications:
Web app shells
A typical app has:
- top navigation or header
- main content area below it
The main content should fill all remaining space.
Admin dashboards
Dashboards often contain:
- a fixed top bar
- a chart/table area that should expand to the rest of the screen
Split panels and editors
Code editors, chat tools, and project management apps often need:
- a header
- a content region
- internal panels with percentage or flexible heights
Scrollable data tables
A page may need:
- header with filters and actions
- content area containing a table
- the table region should scroll while the header stays visible
Mobile and desktop responsive layouts
Modern responsive UIs often avoid old table layouts and instead use Flexbox because it adapts better across screen sizes.
Real Codebase Usage
In real projects, developers usually solve this with a small set of repeatable layout patterns.
Common layout wrapper pattern
.app {
height: 100vh;
display: flex;
flex-direction: column;
}
.app-main {
flex: 1;
min-height: 0;
}
This creates a reusable application shell.
Scroll only the content area
.app-main {
flex: 1;
min-height: 0;
overflow: auto;
}
This keeps the header visible while only the main region scrolls.
Nested flex layouts
A content area often contains more flexible sections:
.content {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.toolbar {
padding: 12px;
}
.results {
: ;
: ;
: auto;
}
Common Mistakes
1. Using height: 100% without giving the parent a height
Broken example:
.content {
height: 100%;
}
If the parent does not have a defined or computed height, this may not work.
Fix
Give the parent a real height source:
.page {
height: 100vh;
}
Then let the content grow with flex:
.page {
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
2. Forgetting to set html and body height when needed
Broken example:
body {
height: 100%;
}
If html does not also have height, the percentage chain may fail.
Comparisons
| Approach | Best for | Handles variable header height well? | Good for percentage children? | Notes |
|---|---|---|---|---|
| HTML table layout | Old layout techniques | Yes | Yes | Works, but not recommended for page layout |
height: calc(100vh - Xpx) | Fixed-size header | No | Yes | Good only when header height is known |
| Flexbox | Vertical or horizontal app layouts | Yes | Yes | Best fit for this problem |
| CSS Grid | More complex page layouts | Yes | Yes | Great when you need rows and columns |
Flexbox vs calc()
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;
}
Key rules
height: 100%needs a parent with a known height.flex: 1makes an element fill remaining space.- Use
flex-direction: columnfor header-above-content layouts. - Use
min-height: 0in nested flex layouts when scrolling is needed. - Prefer Flexbox or Grid over table-based layout.
Useful alternatives
Fixed header height:
.content {
height: calc(100vh - 80px);
}
FAQ
Why does height: 100% not work on my div?
Because the browser needs a defined parent height to calculate 100%. If the parent height is auto, the percentage may not resolve as expected.
What is the best modern way to fill the remaining screen height?
Usually Flexbox. Set the page container to display: flex, use flex-direction: column, and give the content area flex: 1.
Can I do this if the header height changes dynamically?
Yes. Flexbox and Grid both handle variable header heights well.
Should I use a table for page layout?
No, not for general page structure. Tables should be used for tabular data. Flexbox or Grid are better layout tools.
How do I make children inside the content area use percentage heights?
Make sure the content area itself has a computable height, typically by placing it inside a flex or grid layout that gives it remaining space.
When should I use calc(100vh - headerHeight)?
Use it only when the header height is fixed and known. If the header height can change, Flexbox is usually better.
Why is my inner panel not scrolling inside a flex layout?
You may need min-height: 0 on the flex item that should shrink and scroll.
Can CSS Grid solve the same problem?
Yes. A common pattern is , where the first row is the header and the second row fills the rest.
Mini Project
Description
Build a simple application shell with a variable-height header and a content area that fills the rest of the viewport. Inside the content area, create two stacked panels that each take up half of the available height. This demonstrates how remaining-height layouts and percentage heights work together in a real interface.
Goal
Create a full-height page where the header uses natural height and the content area fills the rest of the screen, with inner sections sized using percentages.
Requirements
- Create a page wrapper that fills the viewport height.
- Add a header whose height is determined by its content.
- Add a content area that fills the remaining height.
- Inside the content area, add two sections that each use 50% of the content height.
- Make the lower section scroll if its content becomes too large.
Keep learning
Related questions
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.
CSS Parent Selector Explained: Selecting a Parent <li> from an <a>
Learn whether CSS has a parent selector, how :has() works, and practical alternatives for styling a parent li from a child anchor.
CSS Previous Sibling Selector: What Exists and How to Work Around It
Learn whether CSS has a previous sibling selector, why it does not, and practical ways to style earlier elements using CSS alternatives.