CSS Transition Auto Height
Page Speed ChecklistCSS 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.
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:
<button class="menu-toggle" type="button" title="Menu">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:
/*--- 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:
visibility:hidden
- Keeps visually-hidden content hidden from screen readers and keyboard navigation - an important accessibility feature.height:0
- Sets the initial value - presumably zero, but adjustable as needed.overflow:hidden
- Keeps content from appearing outside the expanding element during the CSS transition.transition
- Sets the desired animation options. Thevisibility
delay and duration of theheight
transition should be the same.transition-delay
- Removes thevisibility
delay for the transition from the closed state to open.
The jQuery
With the open and closed states managed in CSS, JavaScript/jQuery adds and removes the .open
class(es) on click:
// 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:
// 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:
// 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:
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 ImagesOn-Demand Embedded Videos
Using embedded YouTube videos? Eliminate the impact on page speed by loading embedded videos on demand:
On-Demand Videos