Skip to content

Instantly share code, notes, and snippets.

@leereamsnyder
Last active March 22, 2017 20:33
Show Gist options
  • Save leereamsnyder/9942868 to your computer and use it in GitHub Desktop.
Save leereamsnyder/9942868 to your computer and use it in GitHub Desktop.
Quick jQuery plugin to fire the correct browser-prefixed 'transitionend' event with a callback
/***********************************
Little utility function for handling single transitionEnd events.
Particularly handy for when you need to remove something from
the DOM after transforming it with an animation
WHY NOT $el.one('transitionend', callback) ????
=============================================
+ "transitionend" is the standardized name, but in some browsers
it may be prefixed or camel-cased. This normalizes that.
+ Browsers that don't do transitions will never fire a transitionend event
on their own. This makes sure the callback fires.
+ Sometimes a browser will just *not* fire the transitionend event to drive you nuts
This makes sure it happens. (This is why you need the duration)
USAGE
==================
$el.onTransitionEnd( duration, callback );
(OR $el.transitionend( duration, callback ) )
After any transition on the element finishes, callback will call once.
Uses .one(), so callback won't be called again.
Currently limited to a single element
I'm looking into supporting collections
OPTIONS
==================
duration [required] INT
- How long in milliseconds before firing the callback
- To avoid duplication with your CSS, you might try to get it like this:
$el.css('transition-duration')
.split(',') // in case of multiple transitions
.shift() // get the first
.replace('s','') // replace "s" (".5s" -> ".5")
.trim()*1000 // trim and convert to ms (".5" -> 500)
- I add 50ms to this before triggering the 'backup' event
in case the browser misses it. It happens!
- For browsers that don't do transitions, I trigger the event
a few ticks (10ms) later.
callback [optional ... but why not?] FUNCTION
- the function to execute after the transition finishes
- attached with $.one(), so it won't fire after another transition
- the callback is called with the jQuery event object, and "this" is the element (as expected)
EXAMPLE
====================
$el = $(this);
$el.onTransitionEnd( 250, function( event ){
$(this).css('display','none');
});
$el.addClass('fadeOut'); // (or whatever would trigger a transition)
SHOUTOUTS
====================
http://www.modernizr.com/
http://blog.alexmaccaw.com/css-transitions
https://github.com/twbs/bootstrap/blob/master/js/transition.js
*************************/
(function(window, $, undefined){
'use strict';
// Checking for CSS transition support
var transitionSupport = false,
transitionEnd = 'fakeTransitionEnd', // this is the fake event name we'll use if there's no transition support
el = document.createElement('div'),
transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd otransitionend', // Opera used both at one point!
'transition' : 'transitionend'
// Microsoft never supported prefixed transitions. IE10 is not prefixed
};
// Loop through the event names and see if one works.
// If so, update transitionSupport to TRUE and update the transitionEnd event name
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
transitionSupport = true;
transitionEnd = transEndEventNames[name];
}
}
$.fn.onTransitionEnd = function( duration, callback ) {
var called = false, $el = $(this);
$el.one( transitionEnd, function(evt) {
called = true;
if (callback && $.isFunction(callback) ) {
// I'm reasonably sure because we're in an event callback,
// "this" for the callback will be the element (as expected in jQuery world)
// Shouldn't hurt to be explicit though (famous last words)
callback.call(this, evt);
}
});
var timeout = function() {
// If we haven't done the callback already, do so now
if ( ! called ) {
$el.trigger( transitionEnd );
}
};
// add a little time to the duration
// if there's no transition support, fire it ASAP
duration = transitionSupport ? duration + 50 : 10;
setTimeout(timeout, duration);
return this;
};
// sugar if you think more like $el.click()
$.fn.transitionend = $.fn.onTransitionEnd;
})(window, jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment