Easy way to detect support for transitionend event without frameworks like jQuery or Modernizr?
Asked Answered
B

2

15

Have anybody out there found a simple way of detecting whether the browser supports the transitionend event or not in vanillaJs, especially in a way that actually works in all major browsers? :(

I have found this unanswered thread in here: Test for transitionend event support in Firefox, and quite a lot of almost working hacks.

Right now I am bulk adding eventlisteners to all the vendor prefixes, and it kind of works out (even though I think it is a hideous approach that hurts my eyes every time I look at it). But IE8 and IE9 does not support it at all, so I need to detect those two, and treat them separately.

I would prefer to do this without browser sniffing, and definitely without huge libraries/frameworks like jQuery

I have made a jsfiddler snippet that illustrates my problem. There is a button that spawns a dialog. When the dialog is removed by clicking close, it is transitioned in top and opacity, and after ended transition it is supposed to display=none. But if the transitionend is never fired (like in IE8 and IE9), the dialog is never removed, making it cover the show dialog button, destroying the UX. If I could detect when transitionend is not working, I could just set the display=none when closing for those browsers.

http://jsfiddle.net/QJwzF/22/

window.listenersSet = false;
window.dialogShouldBeVisible = false;

window.showMyDialog = function () {
    var myDialog = document.getElementById('dialog'),
        myClose = document.getElementById('close');
    if (!listenersSet) {
        if (!window.addEventListener) { // IE8 has no addEventListener
            myclose.attachEvent('onclick', function () {
                hideMyDialog();
            });
        } else {
            myClose.addEventListener('click', function () {
                hideMyDialog()
            });

            ['webkitTransitionEnd','oTransitionEnd', 'otransitionend', 'transitionend'].forEach(function (eventName) {
                myDialog.addEventListener(eventName, function (e) {
                    if (e.target === myDialog && e.propertyName === 'top') { // only do trigger if it is the top transition of the modalDialog that has ended
                        if (!dialogShouldBeVisible) {
                            myDialog.style.display = 'none';
                            e.stopPropagation();
                        }
                    }
                });
            });
        }
        listenersSet = true;
    }

    myDialog.style.display = 'block';
    myDialog.style.top = '15px';
    myDialog.style.opacity = '1';
    dialogShouldBeVisible = true;
}

window.hideMyDialog = function () {
    var myDialog = document.getElementById('dialog'),
        myClose = document.getElementById('close');
    myDialog.style.top = '-5%';
    myDialog.style.opacity = '0.1';
    dialogShouldBeVisible = false;
}

It is working in Opera, Firefox, Chrome and IE10, but not in IE8 and IE9 (afaik)

If I did a bad job explaining my problem, please let me know, and I will try do a better job! :)

Brunell answered 28/10, 2013 at 13:23 Comment(0)
A
8

I would definitely use this small script available on Github. It's listed among Modernizr "Cross-browser polyfills" page so it can be trusted but Modernizr itself is not required.

The examples in the Github page of the script are written using jQuery (and I can't understand why) but jQuery is also not required as it's written in vanilla js.

Like so you'll have a useful whichTransitionEnd method available. I can't test it right now being on my laptop without IE8/IE9 available but I guess that this method will return false (or anything falsy) in those browsers.

var transition = transitionEnd(box).whichTransitionEnd(); 
// return for example "webkitTransitionEnd"

It will then be quite easy to target those browsers where transitions (and thus transitionend events) are not supported. Hope this will be a nudge in the right direction.

EDIT

After tweaking with the above code the OP came up with a much shorter version of the original script. It saves a good deal of bytes and only detects support for this event, and, in case it's supported returns the name of the event itself.

You can find it here as a gist and read more about it in the comments to this answer.

Aurelio answered 29/10, 2013 at 1:52 Comment(8)
Nifty little tool - In my preliminary tests, I haven't succeeded in breaking this with any browser yet. Thanks a bunch Nobita (and EvandroLG) - it looks more like a home run than a nudge in the right direction! ;-)Brunell
Ahahah that's great, glad it helped!Aurelio
Now that I actually have the correct event name, I dropped the part about writing to all possible event names, and only write a handler to the effective one. Unfortunately it seems that this script gets IE10 wrong, so it has a transitionEnd name, but it is the wrong one. My quick'n'dirty fix for now is to go back to writing a handler to all known event names. :-6 (There is always something!) Still way better off than when I started! :)Brunell
I have also found a use of Array.indexOf that makes IE8 stop executing the script. I have posted an issue in github, with 2 suggested fixes. :)Brunell
OK - now I finally got to read the darn thing through, and if (as me) you only want to know whether or not the browser supports transitionEnd, and if so, what name the event is called, I have extracted the core of that script (and skipped support for testing all elements, and the cache and stuff like that. This script is not far as general and usefull as the original, but to only get the name of the event, it works and it takes up far less bytes: gist.github.com/O-Zone/7230245Brunell
That's great. I updated the answer as this is a far better way to solve the problem, please check if everything's fine in my edit. You can edit it of course. Really appreciate you kept coming back posting your results.Aurelio
Why had nobody voted this up until me? While I did so, I found the gist did not work, because Chrome uses 'transition' and not 'WebkitTransition', yet still uses 'webkitTransitionEnd'. What a mess. But this got me on track to cheat bit - I tested for WebkitTransform, and if so, assume 'webkitTransitionEnd'. Regardless, something needs to be updated when Chrome fixes this.Cisneros
Thanks - I'm glad if I have been to any help. The gist still does the trick for me, since I am only interested in transitionEnd. But yes - it sounds like Chrome is a bit inconsistent there. :)Brunell
R
12

Copied from bootstrap transition, it not only returns true if browser supports transition but also returns proper name of event

  function transitionEnd() {
    var el = document.createElement('div')//what the hack is bootstrap

    var transEndEventNames = {
      WebkitTransition : 'webkitTransitionEnd',
      MozTransition    : 'transitionend',
      OTransition      : 'oTransitionEnd otransitionend',
      transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return transEndEventNames[name];
      }
    }

    return false // explicit for ie8 (  ._.)
  }

Hope this helps.

EIDT: I modified a little bit default bootstrap function so it doesn't return object but string.

Ranit answered 19/9, 2014 at 15:12 Comment(5)
why do you check for event name in style property of an element? why would an event name be there? I'm puzzled by this.Lan
From what I know if browser supports transition it supports transitionend and I am not checking for "transitionend" keyword in style but for "transition". I am returning however transitionend modified with prefix.Ranit
I see. it's a nice way to assume one thing from another, but this works specifically with transitionEndLan
to be honest, transitionEnd is sub functionality of transition. Although assuming that transition API means having transitionEnd too is wrong, as long as you know that there was no browsers that implemented it another way in the past, you can easily have a future proof solution.Ranit
that's how I see that.Ranit
A
8

I would definitely use this small script available on Github. It's listed among Modernizr "Cross-browser polyfills" page so it can be trusted but Modernizr itself is not required.

The examples in the Github page of the script are written using jQuery (and I can't understand why) but jQuery is also not required as it's written in vanilla js.

Like so you'll have a useful whichTransitionEnd method available. I can't test it right now being on my laptop without IE8/IE9 available but I guess that this method will return false (or anything falsy) in those browsers.

var transition = transitionEnd(box).whichTransitionEnd(); 
// return for example "webkitTransitionEnd"

It will then be quite easy to target those browsers where transitions (and thus transitionend events) are not supported. Hope this will be a nudge in the right direction.

EDIT

After tweaking with the above code the OP came up with a much shorter version of the original script. It saves a good deal of bytes and only detects support for this event, and, in case it's supported returns the name of the event itself.

You can find it here as a gist and read more about it in the comments to this answer.

Aurelio answered 29/10, 2013 at 1:52 Comment(8)
Nifty little tool - In my preliminary tests, I haven't succeeded in breaking this with any browser yet. Thanks a bunch Nobita (and EvandroLG) - it looks more like a home run than a nudge in the right direction! ;-)Brunell
Ahahah that's great, glad it helped!Aurelio
Now that I actually have the correct event name, I dropped the part about writing to all possible event names, and only write a handler to the effective one. Unfortunately it seems that this script gets IE10 wrong, so it has a transitionEnd name, but it is the wrong one. My quick'n'dirty fix for now is to go back to writing a handler to all known event names. :-6 (There is always something!) Still way better off than when I started! :)Brunell
I have also found a use of Array.indexOf that makes IE8 stop executing the script. I have posted an issue in github, with 2 suggested fixes. :)Brunell
OK - now I finally got to read the darn thing through, and if (as me) you only want to know whether or not the browser supports transitionEnd, and if so, what name the event is called, I have extracted the core of that script (and skipped support for testing all elements, and the cache and stuff like that. This script is not far as general and usefull as the original, but to only get the name of the event, it works and it takes up far less bytes: gist.github.com/O-Zone/7230245Brunell
That's great. I updated the answer as this is a far better way to solve the problem, please check if everything's fine in my edit. You can edit it of course. Really appreciate you kept coming back posting your results.Aurelio
Why had nobody voted this up until me? While I did so, I found the gist did not work, because Chrome uses 'transition' and not 'WebkitTransition', yet still uses 'webkitTransitionEnd'. What a mess. But this got me on track to cheat bit - I tested for WebkitTransform, and if so, assume 'webkitTransitionEnd'. Regardless, something needs to be updated when Chrome fixes this.Cisneros
Thanks - I'm glad if I have been to any help. The gist still does the trick for me, since I am only interested in transitionEnd. But yes - it sounds like Chrome is a bit inconsistent there. :)Brunell

© 2022 - 2024 — McMap. All rights reserved.