Table Of Contents
Animating from Zero to Auto Height with Details and Summary
Animating height has been one of CSS’s persistent challenges. You can’t transition from height zero to height auto because auto isn’t a numeric value the browser can interpolate. For years, this meant JavaScript height calculations or fixed max-height hacks. But modern CSS finally gives us proper tools to animate to and from auto height, and it’s wonderfully straightforward.
The Height Animation Problem Explained
Here’s the issue: CSS transitions need concrete numbers to work with. When you tell the browser to transition from height: 0 to height: auto, you’re asking it to animate from zero pixels to… what exactly? The browser doesn’t know the final height until it measures the content. And it can’t create a smooth animation between a number and an unknown value.
For years, we’ve relied on the max-height hack. You’d set max-height: 0 on the collapsed state and something like max-height: 500px on the expanded state. The problem? If your content is only 100px tall, the browser still animates through 500px worth of height, making the timing feel completely wrong. Short content snaps open instantly while you wait forever for the remaining 400px of nothing to “animate.” It’s clumsy and impossible to time correctly.
The Perfect Use Case
The details and summary elements are semantic HTML for disclosure widgets—click the summary to toggle the content. They’re built into browsers, keyboard accessible by default, and work without any JavaScript. Perfect bones for an FAQ or accordion interface.
But here’s the thing: they don’t animate by default. They just snap open and closed. Modern CSS now lets us add buttery smooth animations while keeping all that semantic goodness and built-in accessibility. The details element gives us the expand/collapse behavior, and CSS gives us the smooth visual transition we’ve been waiting for.
The Real Hero: calc-size()
Here’s where it gets good. CSS now includes calc-size(), which allows calculations with intrinsic sizing keywords like auto. The syntax calc-size(auto, size) essentially tells the browser: “calculate what auto resolves to, then give me that as an actual number I can transition.” Finally! The browser can create smooth intermediate frames because it knows both the start and end values.
Combined with the ::details-content pseudo-element, we can target exactly the collapsible portion of the details element and apply our height transition. The browser calculates the final height behind the scenes, and calc-size makes that value transition-friendly. No more guessing, no more max-height hacks, just proper height animations that actually work.
The Implementation
The demo uses details elements styled as FAQ items. Each has a summary (the question) and collapsible content (the answer). The default state has block-size: 0 with overflow hidden—completely collapsed. When opened, block-size transitions to calc-size(auto, size), and the content smoothly reveals itself.
The transition also uses transition-behavior: allow-discrete to handle the discrete state change between open and closed. Without this property, the browser wouldn’t animate certain properties that don’t normally transition. It’s a small but crucial piece that makes everything work together.
Demo
View on Codepen (opens in a new tab)
Visual Polish with SVG Filters
Beyond the animation mechanics, the demo adds visual interest with SVG filters creating hand-drawn border effects. These filters are applied via filter url() and alternate between details elements for variety. The borders get that organic, slightly imperfect look that adds personality.
The transform scale on open creates a subtle emphasis effect. Combined with the box-shadow intensification, opening a details element feels like it’s lifting off the page. These small touches make the interaction feel polished and intentional.
The Rotation Indicator
The summary element has a ::before pseudo-element with a custom arrow icon. When the details opens, this rotates 90 degrees via transition. It’s a clear affordance showing that the element is expandable and indicating current state.
The rotation uses absolute positioning with inset properties for precise placement. The transition is smooth and complements the height animation timing. Everything feels coordinated and deliberate.
Staggered Animations
The demo includes a CSS custom property —i that varies per item. This creates staggered animation timing, so opening multiple details in sequence has a cascading effect. It’s a subtle detail that adds rhythm to the interface.
This kind of orchestration is only possible with CSS custom properties. For now at least, with upcoming CSS features like sibling-index (opens in a new tab) and sibling-count we don’t need these hacks anymore.
Anyway, for now you have to do it this way. You can pass numeric values through the cascade and use them in calculations. It’s a powerful technique for coordinating animations across multiple elements.
Background Color Transitions
When opened, details elements transition to a bright yellow background. This uses the same transition timing as the height animation, creating a unified effect. The color change helps distinguish open items from closed ones at a glance.
The combination of height, scale, shadow, and color creates a multi-dimensional transition. It’s not just expanding; it’s emerging. The element feels like it’s coming forward in Z-space even though it’s a 2D transform.
Accessibility Considerations
The details element is keyboard accessible by default. Tab to the summary, press Enter or Space to toggle. Screen readers announce the expanded state automatically. This is why semantic HTML matters: you get accessibility for free.
The visual animations enhance usability for sighted users without breaking the experience for keyboard or screen reader users. Everyone gets a functional disclosure widget; sighted users get a prettier one.
Performance Characteristics
Height transitions can be expensive because they trigger layout recalculation. The browser has to reflow surrounding content as the element expands. For a few details elements on a page, this is fine. For hundreds, you might notice jank.
The scale transform is GPU-accelerated and doesn’t affect layout, so it animates smoothly. Combining a subtle scale with the height transition helps minimize the perceived cost of the layout shift.
Browser Support
The calc-size function is relatively new and has limited support as of late 2024. For browsers without support, you can fall back to max-height transitions or JavaScript. The details functionality works everywhere, just without smooth animations.
The ::details-content pseudo-element is also new. In unsupported browsers, you might need to wrap the content in a div and target that instead. The technique adapts to different support levels gracefully.
Comparing to Alternatives
JavaScript solutions calculate height manually and set explicit pixel values. This works but requires measurement, state management, and careful coordination with CSS. It’s more code and more fragile.
The max-height technique works without JavaScript but has timing issues and requires guessing at maximum content height. If you guess too high, animations feel sluggish. Guess too low, and content gets clipped.
Styling the Summary
The summary element acts as a button but can be styled like any other element. The demo uses padding, font sizing, and positioning to create a clear, tappable target. The cursor pointer reinforces clickability.
You can customize the marker (the default triangle icon) by setting it to none and providing your own indicator. The demo uses a custom SVG arrow instead of the native marker, giving complete control over appearance.
Content Considerations
The animation works regardless of content height. Short content animates quickly, tall content takes longer, but the timing is proportional. This is the advantage over max-height: the transition duration actually means something consistent.
For extremely tall content, you might want to cap the transition duration to prevent overly long animations. This requires careful tuning based on your specific use case and content characteristics.
Multiple Details Groups
When you have multiple details elements, consider whether they should auto-close when another opens. This accordion behavior requires JavaScript to listen for toggle events and close siblings. The details element doesn’t provide this natively.
For independent details that can all be open simultaneously, no JavaScript needed. The native behavior works perfectly. Choose based on your UI requirements and content density.
Customizing Timing
The demo uses a 0.5s transition duration. This feels snappy without being jarring. Shorter durations make the interface feel responsive. Longer durations let users track the content appearing. Find the sweet spot for your specific use case.
The easing function matters too. ease-in-out provides smooth acceleration and deceleration. linear feels mechanical. cubic-bezier allows custom curves. Experiment to find what feels right for your interface personality.
Print Styles
For print, you probably want all details open by default. A simple details { display: block; } in your print stylesheet ensures content is visible on paper. The browser won’t try to animate during print rendering.
This is another advantage of semantic HTML. The details element has clear meaning that can be interpreted differently in different media contexts.
Progressive Enhancement
Start with functional HTML. The details element works without CSS. Add styling for visual polish. Add animations for enhanced interactions. Each layer improves the experience without breaking the foundation.
This approach ensures your interface works for everyone, regardless of browser capabilities or user preferences. It’s resilient, accessible, and future-friendly.
Using in Components
This pattern works beautifully in component-based frameworks. The details element maps cleanly to a Disclosure or Accordion component. The HTML provides structure, CSS provides animation, and JavaScript (if needed) provides coordination.
Keep the semantic HTML as your foundation. It’s tempting to recreate everything with divs and ARIA attributes, but details gives you so much for free. Build on the platform.
Future Enhancements
As browser support for calc-size improves, this technique will become the standard approach for height animations. The max-height hack will fade away. Developers will wonder why we ever tolerated imprecise animations.
Container animations may provide even more control in the future, allowing fine-tuned coordination between container size changes and child element transitions. The platform continues evolving.
Getting Started
To implement this pattern, use semantic details and summary elements. Style them to match your design. Add the calc-size transition on ::details-content. Enable transition-behavior allow-discrete. Test across browsers and adjust fallbacks as needed.
The fundamentals are straightforward. The polish comes from coordinating transitions, adding visual effects, and tuning timing. Start simple and iterate based on user feedback.
Final Thoughts
The combination of semantic HTML and modern CSS creates elegant solutions to long-standing problems. Height animations don’t require JavaScript anymore. The details element provides structure and behavior. CSS provides polish and personality.
This represents the maturation of web platform capabilities. We can build better interfaces with less code, more accessibility, and cleaner architecture. It’s an exciting time to work with CSS.