Search code examples
javascriptbrowser-feature-detectiontransitionend

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


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! :)


Solution

  • 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.