๐Ÿง™โ€โ™‚๏ธ CSS trick: transition from height 0 to auto!
Francesco Vetere

Francesco Vetere @francescovetere

About: Frontend Dev particularly passionate about Web Design and the CSS world ๐Ÿ˜„

Joined:
Nov 2, 2023

๐Ÿง™โ€โ™‚๏ธ CSS trick: transition from height 0 to auto!

Publish Date: Nov 25 '23
485 68

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">
    <div>
      <p>Lorem ipsum ...</p>
    </div>
  </div>
</div>


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 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! ๐Ÿ‘‹

Buy Me A Coffee

Comments 68 total

  • Anita Olsen
    Anita OlsenNov 25, 2023

    Thank you for this! I saved this for later so I can come back to it!

    • Francesco Vetere
      Francesco VetereNov 25, 2023

      Thanks to you for stepping by, I really appreciate it! ๐Ÿ˜Š

  • Gyau Boahen Elvis
    Gyau Boahen ElvisNov 25, 2023

    I was having this trouble building the FAQs section of this landing page I was working on, I had to result to the max-height property. Will try this neat trick and see

    Thank you for the insight

    • Francesco Vetere
      Francesco VetereNov 25, 2023

      Awesome, glad to hear that! Thanks for stepping by! ๐Ÿ˜Š

  • Yeom suyun
    Yeom suyunNov 25, 2023

    I used margin instead of height transition to implement height transition in a multi-level menu, but I think gtr can also be used in this case.

  • fazicodes
    fazicodesNov 25, 2023

    I once used this grid technique and it's perfect๐Ÿ‘

  • Pasquale De Lucia
    Pasquale De LuciaNov 25, 2023

    I love this solution to a common problem! ๐ŸŽ‰

  • freebian666
    freebian666Nov 25, 2023

    Awesome! I really love CSS and use it instead of JS every time when I can. Thank you!

  • Bilal
    BilalNov 25, 2023

    Good by jquery.slideDown() !

  • Sergdan1992
    Sergdan1992Nov 25, 2023

    Hi, there!
    I get it from phone, itโ€™s not working (

  • Shamim Bin Zahid
    Shamim Bin ZahidNov 26, 2023

    there is one very niche specific problem with this what almost no one will face. If you happen to have a meatball menu in this click-or-hover-to-expand component, the menu will be cropped because of the overflow hidden property. I am yet to find a solution for this. Using html details and summary tags may be a nice way of doing it. havenโ€™t tried tho.

    great post btw ๐ŸŒป

    • Francesco Vetere
      Francesco VetereNov 26, 2023

      I don't think I completely understood the scenario you're describing: could you provide an example of this, or a codepen where this situation happens?

  • pizarrosch
    pizarroschNov 26, 2023

    Thank you for this brilliant article! It is a very helpful information ๐Ÿ™‚

    • Francesco Vetere
      Francesco VetereNov 26, 2023

      Glad you liked it, an thanks for stepping by! ๐Ÿ˜

  • Sunday
    SundayNov 26, 2023

    Thank you for sharing!!! I'm enjoying it

  • Adaptive Shield Matrix
    Adaptive Shield MatrixNov 26, 2023

    Why not use the browser native element of ?
    developer.mozilla.org/en-US/docs/W...

    You have to style it yourself and do not need any facy grid workarounds for that

    Supported by all browsers: ~98% support - caniuse.com/details

    Compared to ~90% of grid-template-rows - caniuse.com/mdn-css_properties_gri...

    • Francesco Vetere
      Francesco VetereNov 26, 2023

      First of all, you can't fully style the details element.
      Second, as said in the very article you linked: "Unfortunately, at this time, there's no built-in way to animate the transition between open and closed."
      These are the reasons

  • Adaptive Shield Matrix
    Adaptive Shield MatrixNov 26, 2023

    Since the accordion does not stay open it can be quite frustrating
    Not very good accessibility

    • Francesco Vetere
      Francesco VetereNov 26, 2023

      This is just an example to show how to animate from height 0 to auto... it's not meant to be an accessible component. The way you trigger this animation is irrelevant. I chose an hover instead of a click event, just to avoid writing any JS.

    • Greg
      GregNov 28, 2023

      Instead of using :hover to trigger show/hide of the hidden <accordion-body>, you could instead use an <input> checkbox element and trigger CSS when it is checked!
      ๐Ÿ˜‰

  • Gourob Das
    Gourob DasNov 26, 2023

    Nibe

  • Lucille Xavier
    Lucille XavierNov 26, 2023

    This is cool, thanks for sharing

  • Nicholas Warwick
    Nicholas WarwickNov 26, 2023

    Really slick solution ๐Ÿ‘Œ

  • Hasan Elsherbiny
    Hasan ElsherbinyNov 26, 2023

    this is great ๐Ÿ‘๐Ÿ‘

  • bojidaryovchev
    bojidaryovchevNov 27, 2023

    something really easy with a bit of JS is to set a CSS variable on the container to keep its scrollHeight and then animate from 0 to scrollHeight, this way u can avoid the overflow hidden part

    • Greg
      GregNov 28, 2023

      I think the goal here in this post is to not use JS, simply CSS Only.
      But great suggestion for an alternative solution!

  • ๐’ŽWii ๐Ÿณ๏ธโ€โšง๏ธ
    ๐’ŽWii ๐Ÿณ๏ธโ€โšง๏ธNov 27, 2023

    Really cool! This is a problem that's been annoying me occasionally and I've never found a good solution without using fixed heights. I have a codepen somewhere with a much more hacky way of achieving this, but I never used that in any real projects because of how ugly it is.

    • Francesco Vetere
      Francesco VetereNov 27, 2023

      I totally understand! My go-to solution has always been using the max-height approach... and yeah, I was not so proud of my code everytime I had to build an accordion ๐Ÿ˜…
      But knowing that this can be now achieved without magic numbering anything and without any JS, just got me hyped up so much!

  • LaercioLopesLL
    LaercioLopesLLNov 27, 2023

    Dude, I had this problem for years, this helped a lot. Thanks.

  • Sunkanmi Fafowora
    Sunkanmi FafoworaNov 28, 2023

    Love it.

  • Greg
    GregNov 28, 2023

    Great post! Thank you ๐Ÿ™

    Small suggestion...
    When simply looking at your HTML DOM Structure for the accordion component, I was wondering why there was an empty <div> within the accordion body, only later to find out it is a necessary element.

    Maybe specify a class on the empty <div> with something like overflow-hidden or accordion-body__required-inner-container (obv this is overkill ๐Ÿ˜†) or something that makes it clear this element is required.

    <div class="accordion">
        <div class="accordion-title">Hover me!</div>
        <div class="accordion-body">
            <div class="accordion-body__overflow">
                <p>No longer do you need to use "max-height" to animate the transition of a hidden element.</p>
            </div>
        </div>
    </div>
    
    Enter fullscreen mode Exit fullscreen mode

    Then, obv update your css:

    .accordion-body__overflow { overflow: hidden; }
    
    Enter fullscreen mode Exit fullscreen mode

    Again, just a suggestion! Great write-up overall!
    โญ๏ธ โญ๏ธ โญ๏ธ โญ๏ธ โญ๏ธ

    • Francesco Vetere
      Francesco VetereNov 28, 2023

      This is a great idea! Giving that div a class makes more clear what the purpose of it really is. And using BEM for it is also a nice touch. Thanks for the tip! ๐Ÿ˜‰

  • Rene D
    Rene DNov 28, 2023

    Great post, thank you for this!

  • Supreecha Jaijumpa
    Supreecha JaijumpaNov 29, 2023

    Nice solution

  • AanTourism
    AanTourismNov 29, 2023

    Transitioning from height: 0 to height: auto in CSS can be achieved using the max-height property. Set max-height to a sufficiently large value (e.g., max-height: 1000px) and use transition on max-height for a smooth height transition effect.
    Best Regards,
    Aantourism

  • AanTourism
    AanTourismNov 29, 2023

    Transitioning from height: 0 to height: auto in CSS can be achieved using the max-height property. Set max-height to a sufficiently large value (e.g., max-height: 1000px) and use transition on max-height for a smooth height transition effect.
    Best Regards,
    Aantourism

  • Onur Uludag
    Onur UludagNov 29, 2023

    Thanks for the article! One alternative could be using transform properties and overflow: hidden to imitate the same behaviour. It might bring performance benefits. But obviously your solution is neater. I will definitely give it a try.

  • Mohammed AlHemyari
    Mohammed AlHemyariNov 29, 2023

    Awesome! clear and straightforward explanation

  • Benjamin CARADEUC
    Benjamin CARADEUCNov 29, 2023

    What a great solution!!!! Love it! ๐Ÿ˜ป๐Ÿ˜ป๐Ÿ˜ป
    I'll drop all the stuff I did with a lot of JS and much less maintainable code, right now !
    Thanks a lot!

  • sammandanu
    sammandanuNov 29, 2023

    Awesome, thank you for sharing this!!

    • Francesco Vetere
      Francesco VetereNov 29, 2023

      Glad you enjoyed it! Thanks for stepping by ๐Ÿ˜‰

  • Aaron Armstrong
    Aaron ArmstrongNov 29, 2023

    Hey there Francesco, thanks for sharing.
    I've just started a Front End Dev bootcamp course and I will definitely be using some of these techniques that you've suggested in the future. - Bookmarked and followed!

    • Francesco Vetere
      Francesco VetereNov 29, 2023

      Thank you so much! This motivates me a lot ๐Ÿ˜

  • Gokul
    GokulNov 30, 2023

    Great...

  • lub-bee
    lub-beeNov 30, 2023

    What are the odds... I was having this problem last night, and I abandon for an approximate solution based on margin and percent... I will try that!

  • Dominic Magnifico
    Dominic MagnificoDec 1, 2023

    This is an excellent solution to a perpetually annoying issue. Great writeup!

  • David Uwagbale
    David Uwagbale Jun 26, 2024

    Awesome, I faced the same issue and had to resort to Js to fix it even though I like using css alone for stuff css can fix by itself.
    Can't wait to try this out ๐Ÿ‘

Add comment