Question
Given this page structure:
<div id="header"></div>
<div id="main">
<div id="navigation"></div>
<div id="content"></div>
</div>
<div id="footer"></div>
The #navigation element appears on the left and #content appears on the right. The content is loaded dynamically with PHP, so its height varies from page to page.
How can #navigation be made the same height as #content without assigning a fixed height to #main?
Short Answer
You will learn why height: 100% does not work when a parent has an automatic height, and how Flexbox can create side-by-side columns that automatically share the height of the tallest column. This is the standard modern solution for a dynamic navigation and content layout.
Concept
A percentage height depends on a parent with a definite, explicitly calculated height.
For example, this does not usually achieve equal columns:
#navigation {
height: 100%;
}
If #main has its default height: auto, its height is determined by its children after they are laid out. CSS therefore has no fixed number from which 100% can be calculated.
The real requirement is not “make navigation 100% high”; it is “make two columns share the height of the tallest column.” Flexbox was designed for this kind of layout.
When #main is a flex container with a horizontal direction, its direct children become flex items. Flex items stretch along the cross axis by default. In a row layout, the cross axis is vertical, so both #navigation and #content stretch to the height of the tallest item.
If dynamic PHP output makes #content taller, #main grows to contain it and the navigation stretches with it automatically.
Mental Model
Think of #main as a tray holding two containers side by side.
#contentis a container whose amount of material changes on every page.#navigationis another container beside it.- The tray grows as tall as the tallest container.
- With Flexbox, the tray tells both containers to extend from the top to the bottom of that shared height.
By contrast, height: 100% is like asking for a container that is “100% of the tray” before the tray's final height has been decided.
Syntax and Examples
Make the parent a flex container:
#main {
display: flex;
}
#navigation {
width: 220px;
background: #e8eef7;
}
#content {
flex: 1;
padding: 1rem;
background: #ffffff;
}
<div id="main">
<nav id="navigation">
<a href="/home">Home</a>
<a href="/about">About</a>
</nav>
<main id="content">
<h1>Page content</h1>
<p>This content can be short or very long.</p>
</main>
</div>
display: flex places the direct children of #main in a row by default.
width: 220pxgives the navigation a fixed column width.flex: 1tells content to use the remaining horizontal space.- The default
align-items: stretchmakes both columns equal in height.
You do not need height: 100% on either child.
Step by Step Execution
Consider this layout:
#main {
display: flex;
}
#navigation {
width: 200px;
background: lightsteelblue;
}
#content {
flex: 1;
background: ivory;
}
<div id="main">
<aside id="navigation">Navigation links</aside>
<section id="content">
<h2>Article</h2>
<p>A long article adds enough text to make this section 700 pixels tall.</p>
</section>
</div>
Execution flow:
- The browser sees
display: flexon#main. - Its direct children,
#navigationand#content, become flex items. - Because no
flex-directionis specified, the items are arranged in a horizontal row. #navigationreceives a width of200px.#contentexpands into the remaining available width because offlex: 1.- The long article makes
#content700 pixels tall. #mainbecomes 700 pixels tall to contain its tallest child.- Flexbox stretches
#navigationto the same 700-pixel height.
If a different PHP page produces more or less content, these measurements are recalculated automatically.
Real World Use Cases
Equal-height columns are useful whenever one panel should visually continue beside a variable-height panel:
- A documentation site with a left table of contents and a long article.
- An admin dashboard with a sidebar beside a report or form.
- A product listing page with filter controls beside dynamically loaded results.
- A help center with category navigation beside an article.
- A chat interface with a conversation area beside user or channel information.
- An application shell where a sidebar background should reach the bottom of the current page content.
The content can come from PHP, a database, an API, a CMS, or JavaScript. CSS only responds to the final rendered content height; it does not matter how the HTML was generated.
Real Codebase Usage
In a real project, use semantic HTML and let the layout container manage the columns:
<main class="page-layout">
<aside class="sidebar" aria-label="Site navigation">
<!-- navigation -->
</aside>
<article class="page-content">
<!-- server-rendered content -->
</article>
</main>
.page-layout {
display: flex;
align-items: stretch;
gap: 1.5rem;
}
.sidebar {
flex: 0 0 16rem;
background: #f4f6f8;
}
.page-content {
min-width: 0;
flex: 1;
}
@media (max-width: 700px) {
.page-layout {
flex-direction: column;
}
}
Common project patterns:
- Use
asidefor complementary navigation andmainorarticlefor the primary content. - Use
flex: 0 0 16remwhen the sidebar should neither grow nor shrink and should remain 16rem wide. - Add
min-width: 0to a flexible content panel when it may contain long text, tables, code blocks, or other wide content. It allows the panel to shrink instead of overflowing the row. - Use a media query to stack columns on small screens.
- Apply the sidebar background or border directly to the stretched sidebar, rather than trying to calculate its height in PHP or JavaScript.
Common Mistakes
Using height: 100% with an auto-height parent
/* Usually not a solution */
#navigation {
height: 100%;
}
100% needs a definite parent height. Since #main grows according to its children, this creates a circular requirement rather than equal-height columns.
Use Flexbox instead.
Forgetting to make the parent a flex container
#navigation {
flex: 0 0 200px;
}
Flex properties only affect an element when its parent has display: flex or display: inline-flex.
#main {
display: flex;
}
Setting align-items: flex-start
#main {
display: flex;
align-items: flex-start;
}
This prevents vertical stretching, so each item stays only as tall as its own content. Omit this declaration or use align-items: stretch.
Using JavaScript to measure and copy heights
// Avoid for ordinary layouts
navigation.style.height = `${content.offsetHeight}px`;
This is fragile: fonts, images, window resizing, and later content updates can change heights. CSS layout tools should handle visual layout whenever possible.
Applying Flexbox to the wrong element
Only direct children of a flex container become flex items. If the sidebar is nested inside another wrapper, apply display: flex to the parent that directly contains the two intended columns.
Expecting equal height after stacking on mobile
When flex-direction: column is used, the cross axis becomes horizontal. The panels normally no longer share equal vertical height, which is generally the desired mobile layout.
Comparisons
| Technique | Best use | Equal dynamic column heights? | Notes |
|---|---|---|---|
height: 100% | A child inside a parent with an explicit height | No, not with an auto-height parent | Percentage heights need a definite containing height. |
| Flexbox | One-dimensional rows or columns | Yes | Best default for a sidebar and content layout. |
| CSS Grid | Page layouts with rows and columns | Yes | Useful when you also need structured rows or multiple columns. |
float: left | Maintaining legacy layouts | Not naturally | Floats were common before Flexbox but need workarounds for equal backgrounds. |
| JavaScript height calculation | Rare, special visual effects | Possible | Avoid for standard layout because it must be updated as content changes. |
A CSS Grid version is also valid:
#main {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
}
Grid items in the same row stretch to the row height by default. Choose Flexbox for a simple two-column layout; choose Grid when the overall layout needs explicit rows and columns.
Cheat Sheet
/* Dynamic equal-height sidebar and content */
.layout {
display: flex;
/* Default: flex-direction: row */
/* Default: align-items: stretch */
}
.sidebar {
flex: 0 0 220px; /* grow | shrink | basis */
}
.content {
min-width: 0;
flex: 1;
}
- Put
display: flexon the shared parent. - Equal vertical stretching applies to the parent's direct children.
- Do not rely on
height: 100%when the parent height isauto. - The default
align-items: stretchcreates equal column heights in a row. - Avoid
align-items: flex-startif you want stretched columns. - Use
flex-direction: columnto stack the layout on narrow screens. - Use
gapfor spacing between columns; it does not stop equal-height stretching.
FAQ
Why does height: 100% not make my sidebar as tall as my content?
A percentage height is calculated from the parent's definite height. When the parent has height: auto, it gets its height from its children, so there is no explicit height for 100% to use.
Does Flexbox require a fixed height on the parent?
No. The parent can grow naturally based on dynamic content. Flexbox then stretches the other flex items to the height of the tallest item.
Do I need to add align-items: stretch?
Usually no. stretch is the default value for align-items in a flex container. Add it explicitly only when it improves readability or overrides another rule.
Will this work when PHP changes the content length?
Yes. PHP generates HTML before the page is sent to the browser. Once the browser renders that HTML, Flexbox calculates the layout using the actual content height.
Can I use CSS Grid instead of Flexbox?
Yes. A two-column grid also gives items in the same row a shared row height. Flexbox is often simpler for one sidebar and one content area.
Why is my sidebar still not stretching?
Check whether the parent has display: flex, whether the sidebar is a direct child of that parent, and whether align-items: flex-start is overriding the default stretch behavior.
Should I use JavaScript to make the heights equal?
Not for a standard two-column layout. Flexbox or Grid handles dynamic height changes more reliably and with less code.
Mini Project
Description
Build a responsive documentation-page layout with a left navigation sidebar and a right article. The article has a variable amount of text, so the sidebar background must automatically extend to the same height without a fixed parent height or JavaScript.
Goal
Create a two-column Flexbox layout in which a fixed-width sidebar matches the dynamic article height and stacks vertically on small screens.
Requirements
Use a parent container that holds a sidebar and an article content area.
Make the sidebar 220px wide on larger screens.
Make the content area fill the remaining horizontal space.
Ensure the sidebar background reaches the full height of the longest column.
Stack the sidebar above the content at viewport widths of 700px or less.
Keep learning
Related questions
Add a Favicon to a Static HTML Page
Learn how to add a favicon to static HTML pages, use correct paths and icon formats, and troubleshoot browser caching and local-file issues.
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.