Reputation: 72425
Webkit's transition end event is called webkitTransitionEnd, Firefox is transitionEnd, opera is oTransitionEnd. What is a good way of tackling all of them in pure JS? Should I do browser sniffing? or implement each one separately? Some other way that hasn't occurred to me?
i.e.:
//doing browser sniffing
var transitionend = (isSafari) ? "webkitTransitionEnd" : (isFirefox) ? "transitionEnd" : (isOpera) ? "oTransitionEnd";
element.addEventListener(transitionend, function(){
//do whatever
},false);
or
// Assigning an event listener per browser
element.addEventListener("webkitTransitionEnd", fn);
element.addEventListener("oTransitionEnd", fn);
element.addEventListener("transitionEnd", fn);
function fn() {
//do whatever
}
Upvotes: 92
Views: 40611
Reputation: 1192
Accepted answer is correct but you don't have to re-create that element again-and-again-and...
Build a global variable and add the function(s):
(function(myLib, $, window, document, undefined){
/**
* @summary
* Returns the browser's supported animation end event type.
* @desc
* @see {@link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/}
* @function myLib.getAnimationEndType
* @return {string} The animation end event type
*/
(function(){
var type;
myLib.getAnimationEndType = function(){
if(!type)
type = callback();
return type;
function callback(){
var t,
el = document.createElement("fakeelement");
var animations = {
"animation" : "animationend",
"OAnimation" : "oAnimationEnd",
"MozAnimation" : "animationend",
"WebkitAnimation": "webkitAnimationEnd"
}
for (t in animations){
if (el.style[t] !== undefined){
return animations[t];
}
}
}
}
}());
/**
* @summary
* Returns the browser's supported transition end event type.
* @desc
* @see {@link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/}
* @function myLib.getTransitionEndType
* @return {string} The transition end event type
*/
(function(){
var type;
myLib.getTransitionEndType = function(){
if(!type)
type = callback();
return type;
function callback(){
var t,
el = document.createElement("fakeelement");
var transitions = {
"transition" : "transitionend",
"OTransition" : "oTransitionEnd",
"MozTransition" : "transitionend",
"WebkitTransition": "webkitTransitionEnd"
}
for (t in transitions){
if (el.style[t] !== undefined){
return transitions[t];
}
}
}
}
}());
}(window.myLib = window.myLib || {}, jQuery, window, document));
Upvotes: 0
Reputation: 3784
Here is a more cleaner way
function transitionEvent() {
// Create a fake element
var el = document.createElement("div");
if(el.style.OTransition) return "oTransitionEnd";
if(el.style.WebkitTransition) return "webkitTransitionEnd";
return "transitionend";
}
Upvotes: 1
Reputation: 312
jquery override:
(function ($) {
var oldOn = $.fn.on;
$.fn.on = function (types, selector, data, fn, /*INTERNAL*/ one) {
if (types === 'transitionend') {
types = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd';
}
return oldOn.call(this, types, selector, data, fn, one);
};
})(jQuery);
and usage like:
$('myDiv').on('transitionend', function() { ... });
Upvotes: 0
Reputation: 24762
As of 2015, this one-liner should do the deal (IE 10+, Chrome 1+, Safari 3.2+, FF 4+ and Opera 12+):-
var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : 'transitionend'
Attaching the event listener is simple:-
element.addEventListener(transEndEventName , theFunctionToInvoke);
Upvotes: 6
Reputation: 72425
As per Matijs comment, the easiest way to detect transition events is with a library, jquery in this case:
$("div").bind("webkitTransitionEnd.done oTransitionEnd.done otransitionend.done transitionend.done msTransitionEnd.done", function(){
// Unlisten called events by namespace,
// to prevent multiple event calls. (See comment)
// By the way, .done can be anything you like ;)
$(this).off('.done')
});
In library-less javascript it gets a bit verbose:
element.addEventListener('webkitTransitionEnd', callfunction, false);
element.addEventListener('oTransitionEnd', callfunction, false);
element.addEventListener('transitionend', callfunction, false);
element.addEventListener('msTransitionEnd', callfunction, false);
function callfunction() {
//do whatever
}
Upvotes: 22
Reputation: 33320
If you use jQuery and Bootstrap $.support.transition.end
will return the right event for the current browser.
It is defined in Bootstrap and used in its animation callbacks, though the jQuery docs say not to rely on these properties:
Although some of these properties are documented below, they are not subject to a long deprecation/removal cycle and may be removed once internal jQuery code no longer needs them.
Upvotes: 8
Reputation: 3764
There's a technique used in Modernizr, improved:
function transitionEndEventName () {
var i,
undefined,
el = document.createElement('div'),
transitions = {
'transition':'transitionend',
'OTransition':'otransitionend', // oTransitionEnd in very old Opera
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
};
for (i in transitions) {
if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) {
return transitions[i];
}
}
//TODO: throw 'TransitionEnd event is not supported in this browser';
}
Then you can just call this function whenever you need the transition end event:
var transitionEnd = transitionEndEventName();
element.addEventListener(transitionEnd, theFunctionToInvoke, false);
Upvotes: 169
Reputation: 73025
I use code like this (with jQuery)
var vP = "";
var transitionEnd = "transitionend";
if ($.browser.webkit) {
vP = "-webkit-";
transitionEnd = "webkitTransitionEnd";
} else if ($.browser.msie) {
vP = "-ms-";
} else if ($.browser.mozilla) {
vP = "-moz-";
} else if ($.browser.opera) {
vP = "-o-";
transitionEnd = "otransitionend"; //oTransitionEnd for very old Opera
}
That lets me use JS to add things by specifying vP concatentated with the property, and if it didn't hit a browser it just uses the standard. The events lets me easily bind like so:
object.bind(transitionEnd,function(){
callback();
});
Upvotes: 0
Reputation: 797
google closure makes sure you don't have to do this. If you have an element:
goog.events.listen(element, goog.events.EventType.TRANSITIONEND, function(event) {
// ... your code here
});
looking at the source of goog.events.eventtype.js, TRANSITIONEND is calculated by looking at the useragent:
// CSS transition events. Based on the browser support described at:
// https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
TRANSITIONEND: goog.userAgent.WEBKIT ? 'webkitTransitionEnd' :
(goog.userAgent.OPERA ? 'oTransitionEnd' : 'transitionend'),
Upvotes: 0
Reputation: 12669
Update
The following is a cleaner way of doing it, and doesn't require modernizr
$(".myClass").one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd',
function() {
//do something
});
Alternatively
var transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd otransitionend',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
}, transitionEnd = transEndEventNames[Modernizr.prefixed('transition')];
This is based on the code suggested by Modernizr, but with the extra event for newer versions of Opera.
http://modernizr.com/docs/#prefixed
Upvotes: 8
Reputation: 23907
The second is the way to go. Only one of those events will fire in every browser, so you can set all of them and it'll work.
Upvotes: 1