CSS Height Transition from Hidden to Dynamic with a Simple Trick

CSS Height Transition: From Hidden to Dynamic with a Simple Trick

If you messed around with CSS for long enough, chances are you've tried at least once to make a transition from height: 0 to auto... only to find out that it doesn't work! 😢

➡️ Luckily, today there is actually a solution to this problem: it uses CSS Grid under the hood, and it is just so easy and it works flawlessly!

Let's start with a practical example. I have built this simple accordion:

The HTML for it is pretty straightforward:

<div class="accordion">
  <div class="accordion-title">Hover me!</div>
  <div class="accordion-body">
      <p>Lorem ipsum ...</p>

Enter fullscreen mode Exit fullscreen mode

If you hover with your mouse over the accordion, you'll notice that a dropdown appears. That's cool, but what if we wanted to make it appear with a nice smooth transition?

I actually tried to do so in the previous codepen by adding a little transition on the height property:

.accordion-body {
  height: 0;
  transition: 500ms height ease;

.accordion:hover .accordion-body {
  height: auto;

Enter fullscreen mode Exit fullscreen mode

❌ Unfortunately, this doesn't work: transitioning from height: 0 to height: auto, as I was saying earlier, is something not possible with CSS.

🤔 How to solve this?

Well, a first solution could be setting the height property to a fixed number, instead of auto.

This would work, but it's not such a great approach: in order to compute this fixed number we would have to resort to JavaScript, in order to calculate how much our .accordion-body is actually tall... not really what we aimed for!

😕 Can we still achieve this effect, but with a CSS-only solution?

💡 Actually, yes! Why don't we just use max-height instead?

.accordion-body {
  max-height: 0;
  transition: 500ms max-height ease;

.accordion:hover .accordion-body {
  max-height: 200px;

Enter fullscreen mode Exit fullscreen mode

This would be the result:

Since we are defining a fixed value for max-height, the browser is now able to perform the transition correctly.

😕 The only problem is that, since we are defining a fixed value for max-height, now the content could potentially overflow:

If you're sure that your content will always be such that it never reaches a certain height... then it's perfectly fine to use this method! Just use an appropriate value for max-height, and you're good to go.

Be aware though, the higher the value for max-height, the weirder the transition gets (try putting a max-height: 1000px in the previous codepen, and see how things change!).

🤔 Can we do better? Can we avoid having any fixed height/max-height in the first place?

🎉 CSS Grid comes to the rescue!

✅ We can actually use a neat trick which basically consists in making a CSS grid with a single grid item.

All we really have to do then, is taking our grid-template-rows and make it transition from 0fr to 1fr: this way, our grid item will transition from 0 to its "natural" height. It's THAT simple:

.accordion-body {
  display: grid; 
  grid-template-rows: 0fr;
  transition: 250ms grid-template-rows ease;

.accordion:hover .accordion-body {
  grid-template-rows: 1fr;

.accordion-body > div {
  overflow: hidden;

Enter fullscreen mode Exit fullscreen mode

This feels a lot cleaner. No fixed heights, no fancy stuff, just our accordion working as expected. Wonderful! 😄

The one caveat to this solution is that you actually need to set an overflow: hidden to the .accordion-body's internal div in order to make this work. In my opinion, this little extra CSS is totally worth it, but let me know in the comments what you think about it!

🎁 Bonus tip

This trick only works because of the animability of grid-template-rows (and, more generally speaking, of grid tracks).

This is quite a recent feature for some browsers: if you visit this page (opens in a new tab) you'll notice that grid tracks animability is something that, for example, only landed in Chrome starting from version 107.

At the time I'm writing this article all major browsers supports this feature, but always check for compatibility first if you want to use this feature in production code!

And that's all! Feel free to leave a comment and let me know if you already knew about this awesome CSS feature! 😉

Till next time! 👋