Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to support transitionend without browser sniffing?

I have some javascript that triggers some style changes that will result in CSS transitions.

How should I hook in a callback that will execute after the transition is complete. Obviously in older browsers it will transition instantly but these will not recognize the transitionend event either.

What is the best way to do this short of binding different events if ($.browser.msie && $.browser.version <= 9) - which I understand is bad practice.

Here is a quick example to illustrate my point:

HTML

<div>test</div>

CSS

div {
    border: 1px solid black;
    transition: width 2s;
    width: 5px
}

.test {
    width: 100px;
}

JS

$(function(){
    $(document).on('transitionend', function(){
        alert('transition complete');
    });
    $('div').addClass('test');
});

Live JS fiddle: http://jsfiddle.net/vsDrH/1/

What is the best way to make this event work in old browsers?

Thanks for any help.

like image 229
Chris Avatar asked May 08 '13 11:05

Chris


2 Answers

You can check if the CSS property is supported in the browser like this:

http://jsfiddle.net/vsDrH/3/

function isSupported(property) {
    return property in document.body.style;
}

$(function(){
    $(document).on('transitionend', function(){
        alert('transition complete');
    });
    $('div').addClass('test');

    if(!isSupported('transition')) {
        $(document).trigger('transitionend');
    }
});
like image 50
thebreiflabb Avatar answered Sep 30 '22 08:09

thebreiflabb


You can take a look at the source code of jQuery Transit. It is very good written and self-explainatory.

The principle there is simple :

  1. You get the name of the transition property, to sniff for the rendering engine of the browser;
  2. Next we have a list with all event names across different browsers, from which you get the name of the event for that specific browser
  3. In any other case, if no transitionend property exists, you should consider implementing a setTimeout timer, for optimal cross-browser efficiency.

Javascript ( directly from : jQuery Transit Source Code )

// Helper function to get the proper vendor property name.
// (`transition` => `WebkitTransition`)

// (1)

function getVendorPropertyName(prop) {
    // Handle unprefixed versions (FF16+, for example)
    if (prop in div.style) return prop;

    var prefixes = ['Moz', 'Webkit', 'O', 'ms'];
    var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1);

    if (prop in div.style) { return prop; }

    for (var i=0; i<prefixes.length; ++i) {
       var vendorProp = prefixes[i] + prop_;
       if (vendorProp in div.style) { return vendorProp; }
    }
}

// (2)

var eventNames = {
  'transition':       'transitionEnd',
  'MozTransition':    'transitionend',
  'OTransition':      'oTransitionEnd',
  'WebkitTransition': 'webkitTransitionEnd',
  'msTransition':     'MSTransitionEnd'
};

var eventName = eventNames[getVendorPropertyName('transition')] || null

// (3)

if ( eventName ) {
    // Use the 'transitionend' event if it's available.
    bound = true;
    element.bind(eventName, cb);
} else {
    // Fallback to timers if the 'transitionend' event isn't supported.
    window.setTimeout(cb, delay);
}

Doing this you will be 100% sure that your transitionEnd event will fire

like image 31
drinchev Avatar answered Sep 30 '22 07:09

drinchev