scttnlsn/backbone.viewkit

Transition end event doesn't always fire

Opened this issue · 8 comments

If the value of the transition property does not change the transition end event does not fire. Use a setTimeout to ensure that an end event is always triggered.

I also noticed that transitionEnd and transforms are only implemented for webkit (which makes sense considering this is aimed at mobile apps). Completely up to your discretion, but this is how I (very hastily) patched this to support latest IE and Firefox (inserted at L216 before assigning var Config = ViewKit.Transition.Config):

    var browser = $.browser;
    var prefix;
    prefix = browser.mozilla === true ? (Math.floor(browser.version) === 11 ? '' : '-moz-') : (browser.msie === true ? '' : '-webkit-');

    function whichTransitionEvent(){
        var t;
        var 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];
            }
        }
    }

    transitionEnd = whichTransitionEvent();

    var Config = ViewKit.Transition.Config = {
        transform: prefix + 'transform',
        transition: prefix + 'transition',
        transitionEnd: transitionEnd
    };

edit: some issues with IE11 reporting as "Mozilla" in $.browser (wtf right?). This now works for Chrome, Chrome Canary, IE10 + IE11 and Firefox.

Nice! Could the prefix be set when checking for the existence of the various transition names?

Not sure what you mean?

When you're setting the prefix you check the browser object (i.e. $.browser.msie, $.browser.mozilla) but when determining the transitionEnd event you loop through a bunch of possible names. I'm just curious why you needed to use those two different techniques since I'm not very familiar with the nuances of all these names.

For example, instead of checking $.browser don't we know that if the transitionEnd event is 'webkitTransitionEnd' then the prefix is '-webkit'? Or are there edge cases where that is not true?

Yeah I guess you could. Didn't find a specific function for it in either Modernizr (Modernizr.prefixed returns a prefixed js-version of css properties, not just the prefix), and wanted some control over it, but I guess this should be fairly easy to write.

Check out how leaflet does it:

https://github.com/Leaflet/Leaflet/blob/master/src/dom/DomUtil.js#L172 and
https://github.com/Leaflet/Leaflet/blob/master/src/dom/DomUtil.js#L139

I wrestled with transitionEnd not firing the whole last week. I worked around it by adding a small random number (Math.random() / 10000) to one of the parameters. Depends on the parameters of course, but it might make the code simpler than using setTimeout.

Thanks @fab1an, adding 0.0001 to scale() transform parameter transitionend event is always fired. Not elegant but functional! ;-)

Here's a solution that I used: because modern browser support multiple background images, you can randomly position a single pixel base64 encoded transparent gif. Every update of the Elements.style repositions this transparent gif. Helpful if you want to always trigger transition without visible change to the element.

background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
background-position: 79px 237px;