Transitionend will not fire with transition duration zero

The CSS transition event ‘transitionend’ will not be fired if the ‘transition-duration’ applied to an element is zero. This might be very logical in the sense that “how can a transition end if it never begins?”.

Still this can pose a problem.

example:

Let’s say you have a list of 40 horizontally aligned images. We can invoke a next operation that will slide the list to the next image in a smooth transition. But we also have a ‘goto’ operation that will move the list from one image to another. In this case, the transition should be instant.

We would like to isolate this behavior into a common function taking to arguments. How far to transform an element on the x-axis and a callback function to be called once the transformation has finished.

The problem is that we cannot depend on ‘transitionend’ being fired and since it is not the responsibility of this function to apply the ‘transition-duration’ then we do not know this value, therefore, needing a bit more code.

This should illustrate what we need to do (jQuery is used for this example).

$.fn.moveIt(x, callback) {

	var element = $(this);
	var durationIsZero = element.css('-webkit-transition-duration') === '0s';

	// We only make use of transitionend if transition duration is more than 0s
	if (!durationIsZero) {

		// transitionEnd callback should only run once for each method call 
		element.one('webkitTransitionEnd', function () {
			callback.call(element);
		});

	}

	// Apply transformation
	element.css('-webkit-transform', 'translate(' + x + 'px, 0px) scale(1)');

	// Styles could come from anywhere thus we need the computed value 
	if (durationIsZero)
		callback.call(element);

}

If the ‘transition-duration’ is different from ‘zero ms’ then we listen for the ‘transitionend’ event and then call the function. If this is not the case we simply call the function directly after having applied the desired transformation knowing there is no need to wait.

This allows us to use this method the same way in both these scenarios. One where an actual duration of 300ms is applied.

// Over 300ms we move 800px after which we log 'finished'
$('.image-list').css('-webkit-transition-duration', '300ms');
$('.image-list').moveIt(800, function () {
	console.log('finished');
});

And one where the duration is zero making it instant.

// Instantly we move 4000px after which we log 'finished'
$('.image-list').css('-webkit-transition-duration', '0');
$('.image-list').moveIt(4000, function () {
	console.log('finished');
});

Speak Your Mind

*