Because CSS doesn't offer styles for
scaleX etc, you can't animate these properties with WAAPI. Instead, you have to animate the full
This isn't just a matter of developer aesthetics. It means it's literally impossible to animate these properties with separate animations, or with different animation options.
Some modern browsers allow
rotate to be defined and animated separately, but even then you can't animate the axis of each.
Motion One still allows the animation of
transform, but adds the ability to animate all transforms individually, for all axes:
Which means you can also animate them with different options:
As a newer part of the WAAPI spec, the
Promise isn't supported in every browser. Motion One will polyfill it in those browsers:
During development of Framer Motion, user testing revealed that most developers find seconds a more approachable unit. So in Motion One, durations are defined in seconds.
In a typical animation library, when an animation has finished, the element (or other animated object) is left in the animation's final state.
But when you call WAAPI's
animate function like this:
This is the result:
The animation ends in its initial state!
WAAPI has an option you can set to fix this behaviour. Called
fill, when set to
"forwards" it will persist the animation beyond its timeline.
But this is discouraged even in the official spec.
fill: "forwards" doesn't exactly change the behaviour of the animation, it's better to think of it keeping the animation active indefinitely. As WAAPI animations have a higher priority than
element.style, the only way to change the element's styles while these animations are active is with more animations!
Keeping all these useless animations around can also lead to memory leaks.
The spec offers two solutions. One, adding a
Promise handler that manually sets the final keyframe target to
The second is to immediately set
element.style to the animation target, then animate from its current value and let the browser figure out the final keyframe itself.
Each approach has pros and cons. But a major con they both share is making the user decide. These are unintuitive fixes to an unintuitive behaviour, and whichever is chosen necessitates a wrapping library because repeating these brittle patterns is bad for readability and stability.
So instead, Motion One's
animate function will actually animate to a value, leaving in its target state once the animation is complete.
animate function returns an
Animation, which contains a
cancel is called, the animation is stopped and "removed". It's as if the animation never played at all:
Motion One adds a
stop method. This cancels the animation but also leaves the element in its current state:
In early versions of the WAAPI spec, two or more keyframes must be defined:
However, it was later changed to allow one keyframe. The browser will infer the initial keyframe based on the current visual state of the element.
Some legacy browsers, including the common WAAPI polyfills, only support the old syntax. Which means if you try and use WAAPI as currently documented, it will throw an error in many older browsers.
animate function automatically detects these browsers and will generate an initial keyframe from
window.getComputedStyle(element) where necessary.
WAAPI has no concept of "interrupting" existing animations. So if one animation starts while another is already playing on a specific value, the new animation simply "overrides" the existing animation.
If the old animation is still running when the new one finishes, the animating value will appear to "jump" back to the old animation.
Motion One automatically interrupts the animation of any values passed to
animate and animates on to the new target:
In WAAPI, cubic bezier easing is defined as a CSS string:
This kind of definition will work in Motion One, but we also allow this shorthand array syntax:
Unlike Firefox or Chrome, Webkit's implementation of WAAPI is still a little buggy.
Part of Motion One as a project is finding and filing bugs in WAAPI across all browsers, and where possible fixing them for users of the library. So far, we've filed a handful of bugs:
- Timing issues between accelerated and non-accelerated animations
- Incorrect keyframe generation
- WKWebView: Major delays for accelerated animations
By using Motion One instead of WAAPI, you won't have to worry about shipping these bugs to users.
In regards specifically to the outstanding accelerated animation bugs, we've sadly made the choice to disable accelerated animations in Webkit until they're fixed.
You can still pass
allowWebkitAcceleration to switch these back on:
But if you choose to do so, we recommend testing such animations in iOS thoroughly, including Safari and Chrome iOS (as different bugs exist in each).
Already the "major delays" bug is fixed in iOS 15, and we'll keep an eye on OS adoption before enabling accelerated animations by default.
Stay updated with the Motion One newsletter. We don't spam, and unsubscription is instant.