Question
I want to make a hidden section slide down using CSS transitions.
The element starts with height: 0 and overflow: hidden. On hover, I change it to height: auto, but instead of animating, it appears instantly.
If I start from a fixed height such as 40px and transition to height: auto, it first animates toward 0 and then suddenly jumps to the final size.
How can I create this expand/collapse effect using CSS only, without JavaScript?
#child0 {
height: 0;
overflow: hidden;
background-color: #dedede;
transition: height 1s ease;
}
#parent0:hover #child0 {
height: auto;
}
#child40 {
height: 40px;
overflow: hidden;
background-color: #dedede;
transition: height 1s ease;
}
#parent40:hover #child40 {
height: auto;
}
h1 {
font-weight: bold;
}
<hr>
<div id="parent0">
<h1>Hover me (height: 0)</h1>
<div id="child0">
Some content<br>
Some content<br>
Some content<br>
Some content<br>
Some content<br>
Some content<br>
</div>
</div>
<hr>
<div id="parent40">
<h1>Hover me (height: 40)</h1>
<div id="child40">
Some content<br>
Some content<br>
Some content<br>
Some content<br>
Some content<br>
Some content<br>
</div>
</div>
Short Answer
By the end of this page, you will understand why height: auto does not animate in CSS, what kinds of values CSS transitions can animate, and the most common CSS-only workaround: animating max-height. You will also see alternatives like transform and learn when each approach is appropriate.
Concept
CSS transitions work best when the browser can calculate both a clear starting value and a clear ending value.
For example, this is easy to animate:
height: 0px; /* start */
height: 200px; /* end */
The browser can generate the intermediate values: 20px, 40px, 60px, and so on.
But auto is different. It is not a fixed numeric value. It means: let the browser calculate the size based on the content and layout. Because of that, CSS cannot interpolate from 0px to auto during a transition.
That is why this does not animate:
height: 0;
transition: height 1s ease;
height: auto;
The browser jumps directly to the final layout instead of animating.
Why this matters
Expandable panels, dropdowns, accordions, menus, FAQ sections, and mobile navigation often need to grow and shrink based on content. Since content height is usually unknown ahead of time, developers often run into this exact limitation.
A common CSS-only workaround is to animate instead of :
Mental Model
Think of CSS transitions like animating a car trip between two addresses with exact coordinates.
height: 0pxis a known location.height: 200pxis another known location.height: autois like saying, "drive to wherever the content decides to be."
The browser cannot smoothly animate toward a destination that is not a fixed number.
Using max-height is like giving the browser a measurable limit instead:
- collapsed:
max-height: 0 - expanded:
max-height: 300px
Now the browser has two concrete numeric values and can animate between them.
Syntax and Examples
The most common CSS-only solution is to animate max-height.
Basic pattern
.panel {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
}
.container:hover .panel {
max-height: 300px;
}
Example
<div class="menu">
<button>Hover me</button>
<div class="panel">
<p>Item 1</p>
<p>Item 2</p>
<p>Item 3</p>
</div>
</div>
Step by Step Execution
Consider this example:
<div class="box">
<h2>Hover me</h2>
<div class="content">Hello<br>Hello<br>Hello</div>
</div>
.content {
max-height: 0;
overflow: hidden;
transition: max-height 1s ease;
}
.box:hover .content {
max-height: 100px;
}
What happens step by step
- The page loads.
.contenthasmax-height: 0, so it is fully collapsed.overflow: hiddenhides anything that does not fit inside that height.- When the user hovers over
.box, the rule becomes active.
Real World Use Cases
This pattern appears in many common UI elements.
Dropdown menus
A navigation menu may reveal links on hover or click.
Accordion sections
FAQ pages often expand and collapse answers of different lengths.
Mobile navigation
A menu panel may open to show a list of routes.
Notification details
A compact card may expand to show more information.
Filter panels
Search interfaces often hide advanced filters until needed.
In all of these cases, the final height depends on content, which is why developers often use max-height or JavaScript-assisted measurement.
Real Codebase Usage
In real projects, developers usually choose one of these patterns:
1. max-height for simple CSS-only UI
Good for:
- small dropdowns
- FAQ sections with predictable size
- simple hover interactions
Pattern:
.section {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.section.is-open {
max-height: 500px;
}
2. JavaScript-measured height for precise animations
When content size is unknown or dynamic, developers often measure the element's scrollHeight and animate to that pixel value.
This avoids guessing a max-height.
3. transform for performance-focused effects
Developers sometimes animate transform because it is often smoother and cheaper for the browser to render. However, this is mainly a visual effect and may not affect surrounding layout as expected.
4. Class-based state changes
In real codebases, hover is often replaced by classes such as .is-open, especially for click-driven interfaces:
Common Mistakes
1. Trying to transition to auto
Broken example:
.panel {
height: 0;
transition: height 0.4s ease;
}
.panel:hover {
height: auto;
}
Why it fails:
autois not an animatable numeric endpoint forheight.
Use this instead:
.panel {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
}
.panel:hover {
max-height: 200px;
}
2. Forgetting overflow: hidden
Broken example:
.panel {
max-height: 0;
transition: max-height ease;
}
Comparisons
| Approach | Can animate smoothly? | Affects layout? | Best for | Limitation |
|---|---|---|---|---|
height: 0 to height: auto | No | Yes | Not recommended | auto is not animatable |
max-height: 0 to max-height: 300px | Yes | Yes | Simple CSS-only expand/collapse | Must guess a large enough max value |
transform: scaleY(0) to scaleY(1) | Yes | Usually no real layout resizing | Pure visual open/close effects | Can look squashed; layout behavior differs |
Cheat Sheet
/* CSS-only expand/collapse pattern */
.panel {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.panel.is-open {
max-height: 300px;
}
Key rules
height: autodoes not transition.heightcan transition only between numeric values like0pxand200px.max-heightis the usual CSS-only workaround.- Add
overflow: hiddento hide collapsed content. - Pick a
max-heightlarge enough for the content.
Useful alternatives
/* Visual-only open effect */
.panel {
transform: scaleY(0);
transform-origin: top;
transition: transform 0.3s ease;
}
{
: ();
}
FAQ
Why can't CSS transition height: auto?
Because auto is not a fixed numeric value. The browser cannot calculate intermediate values between 0px and auto.
What is the best CSS-only replacement for height: auto animation?
Usually max-height with overflow: hidden.
Is max-height a perfect solution?
No. You must choose an upper limit, and if the content grows beyond it, the content may be clipped.
Can I use display: none and transition it?
No. display is not animatable.
Should I use hover for dropdowns?
For simple desktop effects, yes. For important navigation or mobile-friendly UI, click-based interactions are usually better.
Is transform: scaleY() better than max-height?
It depends. transform can be smoother visually, but it does not behave like true layout expansion.
When should I use JavaScript instead?
Mini Project
Description
Build a simple FAQ item that expands and collapses using only CSS. This demonstrates the common max-height technique for creating a slide-down effect when the content height is not known in advance.
Goal
Create a CSS-only expandable answer panel that smoothly opens and closes without using height: auto in the transition.
Requirements
- Create a question-and-answer block with a visible title.
- Keep the answer hidden by default.
- Reveal the answer with a smooth animation using CSS only.
- Prevent hidden content from overflowing while collapsed.
- Use a technique that works around the
height: autolimitation.
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.