CSS Transition Auto Height

Page Speed Checklist

CSS Transition With A Little Help From jQuery

Enable a real CSS transition to and from height:auto by filling in the natural height of the element during the transition with a bit of jQuery.

There are any number of potential use cases for a transition to and from height:auto, for example a simple expanding/collapsing menu:

Along with using CSS to animate the transition, one of the benefits of this technique is that the HTML and CSS are exactly as they would be if a native CSS transition to/from height:auto was supported. A bit of jQuery simply fills in the element's natural height during the transition.

Jump To The Code

The HTML

The exact configuration can be adjusted as needed, but most cases will include the content element to be transitioned and a clickable element, like a button, to trigger the CSS transition to height:auto.

For example the expanding/collapsing menu from above:

HTML
<button class="menu-toggle" type="button">Menu</button>

<ul class="menu">
    <li><a href="...">Menu Item A</a></li>
    <li><a href="...">Menu Item B</a></li>
    <li><a href="...">Menu Item C</a></li>
    <li><a href="...">Menu Item D</a></li>
</ul>

The CSS

The open and closed states, including height values and transition options are managed entirely in CSS - arguably as they should be - and applied with an .open class.

The clickable toggle element and the expanding element can be otherwise styled as desired, but the basic functionality includes the open and closed states and transition values:

CSS
/*--- button ---*/
.menu-toggle {...}

    /*--- open state ---*/
    .menu-toggle.open {...}

/*--- menu ---*/
.menu {visibility:hidden;height:0;overflow:hidden;transition:visibility 0s .2s, height .2s}

    /*--- open state ---*/
    .menu.open {visibility:visible;height:auto;transition-delay:0s}

Each CSS declaration in more detail:

The jQuery

With the open and closed states managed in CSS, JavaScript/jQuery adds and removes the .open class(es) on click:

jQuery
// menu reveal
$('.menu-toggle').on('click', function(){
    $(this).add('.example-menu').toggleClass('open');
});

The HTML, CSS and jQuery we have so far expands and collapses, but the CSS height property doesn't natively transition to the auto value so the transition to and from the .open state is instantaneous, rather than with the desired animated CSS transition.

A Little Razzle Dazzle

Fortunately, a little jQuery with the transitionend event and the .scrollHeight property can make up the difference.

Open, close and combined functions form a reusable mini-plugin:

jQuery
// open --------------
function heightopen(){
    $(this).height($(this).get(0).scrollHeight).addClass('open'); // get height and open
    $(this).one('transitionend', function(){ // after transition complete
        $(this).height(''); // revert to CSS-set height
    });
}

// close --------------
function heightclose(){
    $(this).height($(this).get(0).scrollHeight).height('').removeClass('open'); // get height and close
}

// open & close based on open state --------------
function heightopenclose(){
    if($(this).hasClass('open')) {
        $(this).each(heightclose); // close
    }
    else {
        $(this).each(heightopen); // open
    }
}

Updated Click Function

With the special jQuery height-based open/close plugin from above in place, there's one last step. The snippet to add/remove the .open class on click can now be updated to use the heightopenclose function:

jQuery
// menu reveal
$('.menu-toggle').on('click', function(){
    $(this).toggleClass('open'); // optionally add an open state to the toggle button
    $('.menu').each(heightopenclose);
});

And that's it. One small snippet of jQuery effectively enables CSS transitions to and from height:auto for any number of use cases.

Here it is in action with a simple expanding/collapsing menu:

Reflow

Although not an issue for absolutely-positioned elements, animated or not, expanding/collapsing or other potential layout shifts should be used sparingly to avoid the performance impact of content reflow.

More Helpful JavaScript

Transitioning to and from height:auto is a great application of jQuery. JavaScript can also improve user experience and page speed.

Lazy Loading Images

Images are often the largest resources on the page, so lazy loading is a valuable strategy to drastically reduce initial-load page weight:

Lazy Load Images

On-Demand Embedded Videos

Using embedded YouTube videos? Eliminate the impact on page speed by loading embedded videos on demand:

On-Demand Videos