Skip to content

Instantly share code, notes, and snippets.

@Mr0grog
Last active August 30, 2018 15:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mr0grog/8740956 to your computer and use it in GitHub Desktop.
Save Mr0grog/8740956 to your computer and use it in GitHub Desktop.
/**
* Transition helper that allows elements to transition from
* scalar sizes (e.g. "2em") to "auto" (or vice versa). This is useful because
* browsers either simply do not animate such transitions or do them poorly.
*
* Requires your CSS to already have the transition defined. This just allows
* it to function without much jankiness.
*
* Usage:
*
* doTransition( someElement )
* .properties( "width", "height" )
* .to( function( element ) {
* element.className = "css for the destination state";
* });
*
* 1. Set it up by calling `transition` with the element you are animating.
* 2. Call `properties` on the result of that call with the name of the
* properties that will animate.
* 3. Call `to` with a function that will move things to the end state of the
* animation. This helper will call it at the right time.
*/
var doTransition = (function( undefined ) {
var el = document.createElement( "fake" ),
transitions = {
"transition": "transitionend",
"OTransition": "otransitionend",
"MSTransition": "msTransitionEnd",
"MozTransition": "transitionend",
"WebkitTransition": "webkitTransitionEnd"
},
transitionProperty,
transitionEvent;
for ( var type in transitions ){
if ( el.style[ type ] !== undefined ) {
transitionProperty = type;
transitionEvent = transitions[ type ];
break;
}
}
function doTransition( element, properties ) {
properties = [].slice.call( arguments, 1 );
var start, end;
return {
// add properties to animate
properties: function( property ) {
properties = properties.concat( [].slice.call( arguments ) );
return this;
},
// Declare the end state we are transitioning to. Optionally pass
// a `this` parameter to be used when calling the callback.
to: function to( goToEndState, context ) {
if ( !transitionEvent ) {
goToEndState.call( context, element );
return;
}
// Measure the starting dimensions
start = properties.reduce( function( start, property ) {
start[ property ] = getComputedStyle( element )[ property ];
return start;
}, {} );
// suppress animation, move to end state, and re-measure
element.style[ transitionProperty ] = "none";
goToEndState.call( context, element );
end = properties.reduce( function( end, property ) {
end[ property ] = getComputedStyle( element )[ property ];
return end;
}, {} );
// Manually reset animating properties to the start state
properties.forEach( function( property ) {
element.style[ property ] = start[ property ];
});
element.offsetLeft;
// Now turn on animation again and animate to the end state
element.style[ transitionProperty ] = "";
properties.forEach( function( property ) {
element.style[ property ] = end[ property ];
});
// When transitions are done, remove manually set styles
element.addEventListener( transitionEvent, function endTransition( event ) {
if ( event.target === element ) {
element.removeEventListener( transitionEvent, endTransition );
element.style[ transitionProperty ] = "none";
properties.forEach( function( property ) {
element.style[ property ] = "";
});
element.offsetLeft;
element.style[ transitionProperty ] = "";
}
})
}
};
}
return doTransition;
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment