Web Animations finished
Table of contents
- Web Animations
- CSS Animations
- The missing
finishedproperty - Feature detect
Web Animations - Dealing with the missing
finishedproperty - Wrap-up
Web Animations
Recently, I came across an interesting fact about Web Animations. For those who are not familiar with this web technology, here's the basic definition from MDN:
The Web Animations API allows for synchronizing and timing changes to the presentation of a Web page, i.e. animation of DOM elements. It does so by combining two models: the Timing Model and the Animation Model.
CSS Animations
In essence, how we web developers animate virtually anything on the web is by using CSS Animations. However, in some of today's real-world use cases, it does not fit really well. This is where Web Animations actually shine. We can control how we run the animation using JavaScript on the web. We can control the speed of the animation, reverse the animation, or even schedule something more important right after an animation easily. It's dope, isn't it? In fact, such a piece of cool tech can be achieved natively in a browser to achieve optimal performance with more granular controls.
The missing finished property
Today's topic is about one of the quite common problems even for a really simple use case, that is, the missing finished property. This may not surprise you because Web Animations can be Promise-based even though it comes with a full suite of event handlers such as oncancel, onfinish, and so on. Using Promises on the web is neat, especially when you need to schedule a series of tasks to be executed at your will either sequentially or in parallel. However, as of today, only Mozilla Firefox 63+ fully implements Web Animations. Google Chrome 83 and below have implemented it for ages, but it is yet to be a complete one. This causes great confusion for all Web Animations adopters as feature detection can be a little bit tricky when it comes to Web Animations.
Feature detect Web Animations
If you are relying on the Promise-based API, this is what you would normally write:
const hasElementAnimate = 'animate' in Element.prototype;
const hasFinished = hasElementAnimate && document.createElement('div').animate([]).finished != null;
if (hasElementAnimate && hasFinished) {
const el = document.body.querySelector('.animatable');
const anim = el.animate([
{ transform: 'translate3d(0, 0, 0)' },
{ transform: 'translate3d(100px, 0, 0)' },
]);
anim.finished.then(() => {
/** Do more stuff when animation completes */
});
} else {
/** Fallback */
}
Dealing with the missing finished property
This shows an obvious signal that you can achieve the same behavior pretty easily without much code, and this is my take on that by leveraging one of the event handlers onfinish:
/** Assuming `Web Animations` is supported partially... */
const el = document.body.querySelector('.animatable');
const anim = el.animate([
{ transform: 'translate3d(0, 0, 0)', opacity: '0' },
{ transform: 'translate3d(100px, 0, 0)', opacity: '1' },
]);
/**
* By passing the `resolve` callback of a `Promise` as the function to the `onfinish` handler,
* the `Promise` fulfills when the animation completes. Technically this is somewhat `finished`.
* Do you agree? 😄
*/
const animTask = new Promise(yay => (anim.onfinish = yay));
animTask.then(() => {
/** Schedule more stuff when animation completes */
});
Wrap-up
I have come up with a technique that is much more straightforward than any polyfills or solutions I have found so far on the Internet. It has been proven to work without breaking anything for my use cases, but your experience may vary (disclaimer!). Maybe someone has come up with such a succinct solution somewhere on the planet, who knows. This is just another little snippet that I wanted to share with my readers who encounter the same problem, and I hope that this simple trick helps make your life easier.
That's it for now. Have a wonderful day ahead, and I'll see you in the upcoming blog post. Peace! ✌️