Question

How to Make a Div Fill Remaining Screen Height in CSS

csshtmlhtml-table

Question

I am building a web application where the main content area should fill the remaining height of the viewport.

The page contains:

  • a header area with a logo and account information
  • a content area 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:

  1. Make the page container as tall as the viewport.
  2. Let the header take its natural height.
  3. Let the content area grow to fill the rest.
  4. Give the content area a definite computed height so percentage-based children can size themselves correctly.

A common pattern looks like this:

  • body or a wrapper gets min-height: 100vh or height: 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:

A child cannot reliably use height: 100% unless its parent has a resolved height.

So the real problem is not just “make this div taller.” The real problem is “create a layout chain where heights are explicitly defined or computable.”

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

Take Quiz

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;
  background: #e5e7eb;
}

.content {
  flex: 1;
  overflow: auto;
  background: #f9fafb;
}

.panel {
  height: 100%;
  background: #dbeafe;
}

What this does

  • .page is exactly as tall as the viewport.
  • .header uses its natural height.
  • .content grows to fill all remaining space.
  • .panel can use height: 100% because .content has a resolved size through flex layout.

Example with two equal sections inside content

<div class="page">
  <header class="header">Header</header>
  <main class="content">
    <div class="top-half">Top</div>
    <div class="bottom-half">Bottom</div>
  </main>
</div>
html, body {
  height: 100%;
  margin: 0;
}

.page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.header {
  padding: 20px;
  background: #ddd;
}

.content {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.top-half,
.bottom-half {
  height: 50%;
}

.top-half {
  background: #c7d2fe;
}

.bottom-half {
  background: #bfdbfe;
}

This works because the .content element has a definite height: it is the remaining viewport height after the header is laid out.

A practical improvement: min-height: 0

In nested flex layouts, add min-height: 0 to the growing area when overflow should work correctly.

.content {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

This is especially useful when content should scroll inside the panel instead of forcing the whole page to grow.

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

  1. html, body { height: 100%; }

    • This allows full-page layouts to inherit height correctly.
  2. .page { height: 100vh; }

    • The page wrapper becomes exactly the height of the viewport.
  3. .page { display: flex; flex-direction: column; }

    • Its children are arranged vertically.
  4. .header is rendered first

    • It takes only the height needed by its contents and padding.
  5. .content { flex: 1; }

    • Flexbox gives all remaining vertical space to .content.
  6. .inner { height: 100%; }

    • Since .content now has a computed height, .inner can fill it.

Example with numbers

Suppose the viewport height is 1000px.

  • header height becomes 200px
  • remaining space is 800px
  • .content gets 800px
  • .inner with height: 100% becomes 800px

If two children inside .content each have height: 50%, each becomes 400px.

That matches the requirement exactly.

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.

Take Quiz

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 {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

This is common in dashboards, tables, search screens, and admin panels.

Guarding percentage heights

If a child must use height: 100%, developers make sure every parent in the chain has a computable height.

For example:

  • viewport height on outer wrapper
  • flex: 1 on content region
  • height: 100% only after that is true

Why table layouts are avoided

Developers generally avoid using HTML tables for page structure because:

  • tables are meant for tabular data
  • they are harder to maintain as layouts grow
  • responsive behavior is less flexible
  • Flexbox and Grid are designed specifically for layout

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.

Fix

html, body {
  height: 100%;
  margin: 0;
}

3. Expecting percentage heights to work through undefined ancestors

Broken example:

<div class="outer">
  <div class="content">
    <div class="child"></div>
  </div>
</div>
.child {
  height: 100%;
}

If .outer and .content do not have computable heights, .child cannot resolve 100% properly.

4. Using tables for layout instead of data

Tables can appear to solve the height problem, but they are the wrong semantic tool for page layout.

Use:

  • Flexbox for one-dimensional layouts
  • Grid for two-dimensional layouts

5. Missing min-height: 0 in nested flex layouts

A common issue is that the scrollable child refuses to shrink.

Fix

.content {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

6. Hard-coding the header height unnecessarily

Broken idea:

.content {
  height: calc(100vh - 120px);
}

This only works if the header is always 120px tall.

If the header height is dynamic, Flexbox is usually better.

Comparisons

ApproachBest forHandles variable header height well?Good for percentage children?Notes
HTML table layoutOld layout techniquesYesYesWorks, but not recommended for page layout
height: calc(100vh - Xpx)Fixed-size headerNoYesGood only when header height is known
FlexboxVertical or horizontal app layoutsYesYesBest fit for this problem
CSS GridMore complex page layoutsYesYesGreat when you need rows and columns

Flexbox vs calc()

  • Use Flexbox when the header height is dynamic.
  • Use calc() when the header height is fixed and known.

Example with calc():

.content {
  height: calc(100vh - 80px);
}

This is simple, but it fails if the header changes height.

Flexbox vs Grid

  • Flexbox is ideal when the layout is mainly one-dimensional, like a vertical stack.
  • Grid is better when you need both rows and columns.

A Grid version could look like this:

.page {
  height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr;
}

This also works well for a natural-height header plus remaining-space content.

Take Quiz

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: 1 makes an element fill remaining space.
  • Use flex-direction: column for header-above-content layouts.
  • Use min-height: 0 in 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);
}

Grid version:

.page {
  height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr;
}

Common debugging checklist

  • Did you set html, body height?
  • Does the outer wrapper have height: 100vh or equivalent?
  • Is the content area using flex: 1?
  • Are percentage-height children inside a parent with a computed height?
  • Do you need min-height: 0 for overflow to behave correctly?

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 grid-template-rows: auto 1fr, where the first row is the header and the second row fills the rest.

Take Quiz

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.
Take Quiz

Keep learning

Related questions

View more